/// <summary> /// Constructs an instance of the SyncSocketReadingStream class. /// </summary> /// <param name="tcpConnectionManager">TCP Connection Manager.</param> /// <param name="tcpSocketInfo">The connection.</param> /// <param name="receiveTimeout">The moment at which the message must be received entirely.</param> /// <param name="automaticallyContinueReading">Indicates whether this instance will automatically initiate reading of the next message from the specified connection.</param> public SyncSocketReadingStream(TcpConnectionManager tcpConnectionManager, TcpSocketInfo tcpSocketInfo, int receiveTimeout, bool automaticallyContinueReading) { this._readBuffer = BufferPool.ObtainBuffer(); this._tcpConnectionManager = tcpConnectionManager; this._tcpSocketInfo = tcpSocketInfo; this._receiveTimeout = receiveTimeout; this._automaticallyContinueReading = automaticallyContinueReading; // first, complete receiving of the first header // it may read up the entire message and release the underlying connection ReadNextPortion(true); }
/// <summary> /// Establishes a connection to the remote host. /// </summary> /// <param name="remote">The HostInformation of the remote host.</param> /// <param name="genuineConnectionType">Type of the connection.</param> /// <param name="localUri">Local URI.</param> /// <param name="localPort">Local port.</param> /// <param name="connectionName">The name of the connection or a null reference.</param> /// <param name="remoteUri">Remote URI.</param> /// <param name="remoteHostUniqueIdentifier">The unique identifier of the HostInformation used by the remote host.</param> /// <returns>A connection.</returns> internal TcpSocketInfo LowLevel_OpenConnection(HostInformation remote, GenuineConnectionType genuineConnectionType, string localUri, int localPort, string connectionName, out string remoteUri, out int remoteHostUniqueIdentifier) { BinaryLogWriter binaryLogWriter = this.ITransportContext.BinaryLogWriter; using (new ReaderAutoLocker(this._disposeLock)) { if (this._disposed) throw OperationException.WrapException(this._disposeReason); } remoteUri = null; Stream inputStream = null; Stream outputStream = null; remoteHostUniqueIdentifier = 0; string url = remote.Url; // parse provided url and fetch a port and IP address int portNumber; string hostName = GenuineUtility.SplitToHostAndPort(url, out portNumber); // LOG: if ( binaryLogWriter != null && binaryLogWriter[LogCategory.Connection] > 0 ) { binaryLogWriter.WriteEvent(LogCategory.Connection, "TcpConnectionManager.LowLevel_OpenConnection", LogMessageType.ConnectionEstablishing, null, null, remote, null, GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name, null, null, -1, 0, 0, 0, null, null, null, null, "The connection is being established to {0}.", hostName); } Socket socket = null; // the time we should finish connection establishing before int timeout = GenuineUtility.GetTimeout( (TimeSpan) this.ITransportContext.IParameterProvider[GenuineParameter.ConnectTimeout] ); using (ConnectionEstablishingClosure connectionEstablishingClosure = new ConnectionEstablishingClosure(hostName, portNumber, this.ITransportContext.IParameterProvider)) { connectionEstablishingClosure.StartOperation(); if (! connectionEstablishingClosure.Completed.WaitOne( GenuineUtility.GetMillisecondsLeft(timeout), false)) throw GenuineExceptions.Get_Connect_CanNotConnectToRemoteHost(url, "Timeout expired."); if (connectionEstablishingClosure.Exception != null) throw GenuineExceptions.Get_Connect_CanNotConnectToRemoteHost(url, connectionEstablishingClosure.Exception.Message); socket = connectionEstablishingClosure.CompleteOperation(); } if (! socket.Connected) throw GenuineExceptions.Get_Connect_CanNotConnectToRemoteHost(url, "Socket.Connected property is false after connecting."); if (connectionName == null) connectionName = "$/__GC/" + hostName; TcpSocketInfo tcpSocketInfo = new TcpSocketInfo(socket, this.ITransportContext, connectionName #if DEBUG ,"Opened connection" #endif ); tcpSocketInfo.GenuineConnectionType = genuineConnectionType; // LOG: if ( binaryLogWriter != null && binaryLogWriter[LogCategory.Connection] > 0 ) { binaryLogWriter.WriteConnectionParameterEvent(LogCategory.Connection, "TcpConnectionManager.LowLevel_OpenConnection", LogMessageType.ConnectionParameters, null, remote, this.ITransportContext.IParameterProvider, GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name, tcpSocketInfo.DbgConnectionId, "The connection is being established to \"{0}\".", hostName); } // send protocol version and the type of the connection Message message = new Message(null, null, -1, new TransportHeaders(), Stream.Null); message.FinishTime = timeout; message.SerializedContent = MessageCoder.SerializeConnectionHeader(MessageCoder.PROTOCOL_VERSION, genuineConnectionType, tcpSocketInfo.ConnectionName).BaseStream; LowLevel_SendSync(message, tcpSocketInfo); tcpSocketInfo.MessagesSentSynchronously.ReleaseAllMessages(); // get connection-level SS string connectionLevelSSName = null; switch(genuineConnectionType) { case GenuineConnectionType.Persistent: connectionLevelSSName = this.ITransportContext.IParameterProvider[GenuineParameter.SecuritySessionForPersistentConnections] as string; break; case GenuineConnectionType.Named: connectionLevelSSName = this.ITransportContext.IParameterProvider[GenuineParameter.SecuritySessionForNamedConnections] as string; break; case GenuineConnectionType.Invocation: connectionLevelSSName = this.ITransportContext.IParameterProvider[GenuineParameter.SecuritySessionForInvocationConnections] as string; break; } SecuritySession securitySession = null; if (connectionLevelSSName != null) securitySession = this.ITransportContext.IKeyStore.GetKey(connectionLevelSSName).CreateSecuritySession(connectionLevelSSName, null); // establish it if (securitySession != null && ! securitySession.IsEstablished) { // LOG: if ( binaryLogWriter != null && binaryLogWriter[LogCategory.Connection] > 0 ) { binaryLogWriter.WriteEvent(LogCategory.Connection, "TcpConnectionManager.LowLevel_OpenConnection", LogMessageType.ConnectionSecurityIsEstablished, null, null, tcpSocketInfo.Remote, null, GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name, securitySession, connectionLevelSSName, tcpSocketInfo.DbgConnectionId, 0, 0, 0, null, null, null, null, "The Connection Level Security Session is being established."); } bool firstPass = true; for ( ; ; ) { inputStream = Stream.Null; try { // prepare streams if (! firstPass) inputStream = this.LowLevel_ReadSync(tcpSocketInfo, timeout, false); else firstPass = false; outputStream = securitySession.EstablishSession(inputStream, true); if (outputStream == null) break; // send a packet to the remote host message = new Message(null, null, -1, new TransportHeaders(), Stream.Null); message.FinishTime = timeout; message.SerializedContent = outputStream; LowLevel_SendSync(message, tcpSocketInfo); tcpSocketInfo.MessagesSentSynchronously.ReleaseAllMessages(); if (securitySession.IsEstablished) break; } finally { if (inputStream != null) inputStream.Close(); if (outputStream != null) outputStream.Close(); } } } tcpSocketInfo.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); // 2.5.2 fix // binaryWriter.Write((int) localPort); binaryWriter.Write((int) -1); binaryWriter.Write((byte) genuineConnectionType); binaryWriter.Write((int) remote.LocalHostUniqueIdentifier); // and send it message = new Message(null, null, -1, new TransportHeaders(), Stream.Null); message.FinishTime = timeout; message.SerializedContent = serializedLocalInfo; LowLevel_SendSync(message, tcpSocketInfo); tcpSocketInfo.MessagesSentSynchronously.ReleaseAllMessages(); // read remote info using (Stream remoteUriStream = this.LowLevel_ReadSync(tcpSocketInfo, timeout, false)) { BinaryReader binaryReader = new BinaryReader(remoteUriStream); remoteUri = binaryReader.ReadString(); remoteHostUniqueIdentifier = binaryReader.ReadInt32(); } } tcpSocketInfo.IsServer = false; return tcpSocketInfo; }
/// <summary> /// Accepts an incoming TCP connection. /// </summary> /// <param name="socket">The socket.</param> /// <param name="localUri">URI of the local host.</param> /// <param name="remoteUri">Uri of the remote host.</param> /// <param name="remoteAddress">Address of the remote host.</param> /// <param name="connectionName">The name of the connection.</param> /// <param name="remoteHostUniqueIdentifier">The unique identifier of the HostInformation used by the remote host.</param> /// <param name="reasonOfStateLost">The reason why the remote host has lost its state (if it's happened).</param> /// <returns>An instance of the TcpSocketInfo class.</returns> internal TcpSocketInfo LowLevel_AcceptConnection(Socket socket, string localUri, out string remoteUri, out string remoteAddress, out string connectionName, out int remoteHostUniqueIdentifier, out Exception reasonOfStateLost) { using (new ReaderAutoLocker(this._disposeLock)) { if (this._disposed) throw OperationException.WrapException(this._disposeReason); } // set the remote end point and local end point using (new ThreadDataSlotKeeper(OccupiedThreadSlots.SocketDuringEstablishing, socket)) { remoteUri = null; remoteAddress = null; remoteHostUniqueIdentifier = 0; Stream inputStream = null; Stream outputStream = null; // the time we should finish connection establishing before int timeout = GenuineUtility.GetTimeout( (TimeSpan) this.ITransportContext.IParameterProvider[GenuineParameter.ConnectTimeout]); // setup a socket LingerOption lingerOption = new LingerOption(true, 3); socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Linger, lingerOption); if ((bool) this.ITransportContext.IParameterProvider[GenuineParameter.TcpDisableNagling]) socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.NoDelay, 1); // create a connection TcpSocketInfo tcpSocketInfo = new TcpSocketInfo(socket, this.ITransportContext, null #if DEBUG ,"Accepted connection" #endif ); // LOG: BinaryLogWriter binaryLogWriter = this.ITransportContext.BinaryLogWriter; if ( binaryLogWriter != null && binaryLogWriter[LogCategory.AcceptingConnection] > 0 ) binaryLogWriter.WriteEvent(LogCategory.AcceptingConnection, "TcpConnectionManager.LowLevel_AcceptConnection", LogMessageType.ConnectionAccepting, null, null, null, null, GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name, null, null, tcpSocketInfo.DbgConnectionId, 0, 0, 0, socket.RemoteEndPoint.ToString(), socket.LocalEndPoint.ToString(), null, null, "An inbound connection is being accepted. Remote end point: {0}.", socket.RemoteEndPoint.ToString()); // receive and analyze protocol version and the type of the connection GenuineConnectionType genuineConnectionType; byte protocolVersion; using (Stream readingStream = this.LowLevel_ReadSync(tcpSocketInfo, timeout, false)) { BinaryReader binaryReader = new BinaryReader(readingStream); MessageCoder.DeserializeConnectionHeader(binaryReader, out protocolVersion, out genuineConnectionType, out connectionName); } // define the connection logic tcpSocketInfo.GenuineConnectionType = genuineConnectionType; tcpSocketInfo.ConnectionName = connectionName; // get connection-level SS string connectionLevelSSName = null; switch (tcpSocketInfo.GenuineConnectionType) { case GenuineConnectionType.Persistent: connectionLevelSSName = this.ITransportContext.IParameterProvider[GenuineParameter.SecuritySessionForPersistentConnections] as string; break; case GenuineConnectionType.Named: connectionLevelSSName = this.ITransportContext.IParameterProvider[GenuineParameter.SecuritySessionForNamedConnections] as string; break; case GenuineConnectionType.Invocation: connectionLevelSSName = this.ITransportContext.IParameterProvider[GenuineParameter.SecuritySessionForInvocationConnections] as string; break; } SecuritySession securitySession = null; if (connectionLevelSSName != null) securitySession = this.ITransportContext.IKeyStore.GetKey(connectionLevelSSName).CreateSecuritySession(connectionLevelSSName, null); // establish a SS if (securitySession != null && ! securitySession.IsEstablished) { // LOG: if ( binaryLogWriter != null && binaryLogWriter[LogCategory.AcceptingConnection] > 0 ) binaryLogWriter.WriteEvent(LogCategory.AcceptingConnection, "TcpConnectionManager.LowLevel_AcceptConnection", LogMessageType.ConnectionSecurityIsEstablished, null, null, null, null, GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name, securitySession, connectionLevelSSName, tcpSocketInfo.DbgConnectionId, 0, 0, 0, null, null, null, null, "The Connection Level Security Session must be established prior to connection is accepted."); for ( ; ; ) { inputStream = null; try { // prepare streams inputStream = this.LowLevel_ReadSync(tcpSocketInfo, timeout, false); outputStream = securitySession.EstablishSession(inputStream, true); if (outputStream == null) break; // send a packet to the remote host Message message = new Message(null, null, -1, new TransportHeaders(), Stream.Null); message.FinishTime = timeout; message.SerializedContent = outputStream; LowLevel_SendSync(message, tcpSocketInfo); tcpSocketInfo.MessagesSentSynchronously.ReleaseAllMessages(); if (securitySession.IsEstablished) break; } finally { if (inputStream != null) inputStream.Close(); if (outputStream != null) outputStream.Close(); } } } tcpSocketInfo.ConnectionLevelSecurity = securitySession; // exchange with connection info int remotePort = 0; // read remote info using (Stream headerStream = this.LowLevel_ReadSync(tcpSocketInfo, timeout, false)) { // this.SkipPacketHeader(headerStream, connectionLevelSSName); BinaryReader binaryReader = new BinaryReader(headerStream); remoteUri = binaryReader.ReadString(); remotePort = binaryReader.ReadInt32(); tcpSocketInfo.GenuineConnectionType = (GenuineConnectionType) binaryReader.ReadByte(); if (protocolVersion >= 0x1) remoteHostUniqueIdentifier = binaryReader.ReadInt32(); } HostInformation remote = this.ITransportContext.KnownHosts[remoteUri]; remote.ProtocolVersion = protocolVersion; // LOG: if ( binaryLogWriter != null && binaryLogWriter[LogCategory.Connection] > 0 ) { binaryLogWriter.WriteConnectionParameterEvent(LogCategory.Connection, "TcpConnectionManager.LowLevel_AcceptConnection", LogMessageType.ConnectionParameters, null, remote, this.ITransportContext.IParameterProvider, GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name, tcpSocketInfo.DbgConnectionId, "The connection is accepted. Protocol version: \"{0}\".", protocolVersion); } reasonOfStateLost = remote.UpdateUri(remoteUri, remoteHostUniqueIdentifier, tcpSocketInfo.GenuineConnectionType == GenuineConnectionType.Persistent); using (GenuineChunkedStream serializedLocalInfo = new GenuineChunkedStream(false)) { // serialize local info BinaryWriter binaryWriter = new BinaryWriter(serializedLocalInfo); binaryWriter.Write((string) localUri); if (protocolVersion >= 0x1) binaryWriter.Write((int) remote.LocalHostUniqueIdentifier); // and send it Message message = new Message(null, null, -1, new TransportHeaders(), Stream.Null); message.FinishTime = timeout; message.SerializedContent = serializedLocalInfo; LowLevel_SendSync(message, tcpSocketInfo); tcpSocketInfo.MessagesSentSynchronously.ReleaseAllMessages(); } // build network address of the remote host if (remotePort > 0) { IPEndPoint remoteHostIpEndPoint = (IPEndPoint) socket.RemoteEndPoint; remoteAddress = "gtcp://" + remoteHostIpEndPoint.Address.ToString() + ":" + remotePort; } tcpSocketInfo.IsServer = true; return tcpSocketInfo; } }
/// <summary> /// Initiates receiving of the message's header. /// </summary> /// <param name="tcpSocketInfo">The connection.</param> internal void LowLevel_HalfSync_StartReceiving(TcpSocketInfo tcpSocketInfo) { if (tcpSocketInfo.ReceivingHeaderBuffer == null) tcpSocketInfo.ReceivingHeaderBuffer = new byte[HEADER_SIZE]; tcpSocketInfo.ReceivingBufferExpectedSize = HEADER_SIZE; tcpSocketInfo.ReceivingBufferCurrentPosition = 0; tcpSocketInfo.IsHeaderIsBeingReceived = true; // LOG: BinaryLogWriter binaryLogWriter = this.ITransportContext.BinaryLogWriter; if ( binaryLogWriter != null && binaryLogWriter[LogCategory.Transport] > 0 ) { binaryLogWriter.WriteEvent(LogCategory.Transport, "TcpConnectionManager.LowLevel_HalfSync_StartReceiving", LogMessageType.ReceivingStarted, null, null, tcpSocketInfo.Remote, null, GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name, tcpSocketInfo.ConnectionLevelSecurity, tcpSocketInfo.ConnectionLevelSecurity == null ? null : tcpSocketInfo.ConnectionLevelSecurity.Name, tcpSocketInfo.DbgConnectionId, 0, 0, 0, null, null, null, null, "The asynchronous receiving is initiated. Requested size: {0}.", tcpSocketInfo.ReceivingBufferExpectedSize - tcpSocketInfo.ReceivingBufferCurrentPosition); } AsyncThreadStarter.QueueTask(new Async_InitiateSocketReceiving(tcpSocketInfo.Socket, tcpSocketInfo.ReceivingHeaderBuffer, tcpSocketInfo.ReceivingBufferCurrentPosition, tcpSocketInfo.ReceivingBufferExpectedSize - tcpSocketInfo.ReceivingBufferCurrentPosition, _HalfSync_onEndReceiving, tcpSocketInfo)); if ( ! tcpSocketInfo.IsServer && (bool) this.ITransportContext.IParameterProvider[GenuineParameter.TcpPreventDelayedAck]) GenuineThreadPool.QueueUserWorkItem(this._lowLevel_Client_PreventDelayedAck, tcpSocketInfo, true); }
/// <summary> /// Processes failed sockets. /// </summary> /// <param name="exception">The source exception.</param> /// <param name="tcpSocketInfo">The socket.</param> private void SocketFailed(Exception exception, TcpSocketInfo tcpSocketInfo) { BinaryLogWriter binaryLogWriter = this.ITransportContext.BinaryLogWriter; try { lock (tcpSocketInfo) { // if connection's resources were released if (! tcpSocketInfo.IsValid) return ; tcpSocketInfo.IsValid = false; tcpSocketInfo.LockForSending = true; } // LOG: if ( binaryLogWriter != null && binaryLogWriter[LogCategory.Connection] > 0 ) { binaryLogWriter.WriteEvent(LogCategory.Connection, "TcpConnectionManager.SocketFailed", LogMessageType.ConnectionFailed, exception, null, tcpSocketInfo.Remote, null, GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name, tcpSocketInfo.ConnectionLevelSecurity, tcpSocketInfo.ConnectionLevelSecurity == null ? null : tcpSocketInfo.ConnectionLevelSecurity.Name, tcpSocketInfo.DbgConnectionId, 0, 0, 0, null, null, null, null, "TCP connection has failed."); } // choose the type of the connection switch (tcpSocketInfo.GenuineConnectionType) { case GenuineConnectionType.Persistent: // determine whether the problem is critical bool criticalError = ConnectionManager.IsExceptionCritical(exception as OperationException) || (int) this.ITransportContext.IParameterProvider[GenuineParameter.ReconnectionTries] <= 0 || ((TimeSpan) this.ITransportContext.IParameterProvider[GenuineParameter.SleepBetweenReconnections]).TotalMilliseconds <= 0; bool queueWasOverflowed = false; lock (tcpSocketInfo) { try { if (tcpSocketInfo.Message != null) { tcpSocketInfo.Message.SerializedContent.Position = 0; tcpSocketInfo.MessageContainer.AddMessage(tcpSocketInfo.Message, false); } tcpSocketInfo.Message = null; } catch(Exception) { // queue is overrun criticalError = true; queueWasOverflowed = true; } try { // it automatically resets the stream position tcpSocketInfo.MessagesSentSynchronously.MoveMessages(tcpSocketInfo.MessageContainer); } catch(Exception) { // queue is overrun criticalError = true; queueWasOverflowed = true; } } // check whether it is a primary connection failure if (! object.ReferenceEquals(tcpSocketInfo, this._persistent.Get(tcpSocketInfo.PrimaryRemoteUri, tcpSocketInfo.ConnectionName)) && ! queueWasOverflowed) { // it's either the previous stub or a parallel connection // close it silently GenuineThreadPool.QueueUserWorkItem(new WaitCallback(this.LowLevel_CloseConnection), tcpSocketInfo, false); return ; } if (criticalError) { // LOG: if ( binaryLogWriter != null && binaryLogWriter[LogCategory.Connection] > 0 ) binaryLogWriter.WriteEvent(LogCategory.Connection, "TcpConnectionManager.SocketFailed", LogMessageType.ConnectionReestablished, exception, null, tcpSocketInfo.Remote, null, GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name, null, null, tcpSocketInfo.DbgConnectionId, 0, 0, 0, null, null, null, null, "The connection cannot be reestablished due to the critical exception."); this.Pool_DestroyPersistentConnection(tcpSocketInfo, exception); return ; } // the error is not critical and the connection will be possibly restored tcpSocketInfo.SignalState(GenuineEventType.GeneralConnectionReestablishing, exception, null); try { // try to reestablish the connection lock (this._persistent.SyncRoot) { TcpSocketInfo existentSocketInfo = this._persistent.Get(tcpSocketInfo.PrimaryRemoteUri, tcpSocketInfo.ConnectionName) as TcpSocketInfo; // FIX 2.5.2. We can reestablish a connection if and only if no connections have been // already established. Otherwise, we can overwrite currently established connection if (ReferenceEquals(existentSocketInfo, tcpSocketInfo)) { lock (tcpSocketInfo) { // create stub connection TcpSocketInfo connectionWithQueue = new TcpSocketInfo(null, this.ITransportContext, tcpSocketInfo.ConnectionName #if DEBUG ,"Stub for the persistent connection while it's being established." #endif ); connectionWithQueue.LockForSending = true; connectionWithQueue.MessageContainer = tcpSocketInfo.MessageContainer; connectionWithQueue.CloseConnectionAfterInactivity = GenuineUtility.ConvertToMilliseconds(this.ITransportContext.IParameterProvider[GenuineParameter.MaxTimeSpanToReconnect]); connectionWithQueue.Remote = tcpSocketInfo.Remote; connectionWithQueue.GenuineConnectionType = GenuineConnectionType.Persistent; connectionWithQueue.IsServer = tcpSocketInfo.IsServer; connectionWithQueue.Renew(); // LOG: if ( binaryLogWriter != null && binaryLogWriter[LogCategory.Connection] > 0 ) binaryLogWriter.WriteEvent(LogCategory.Connection, "TcpConnectionManager.SocketFailed", LogMessageType.ConnectionReestablishing, exception, null, tcpSocketInfo.Remote, null, GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name, null, null, connectionWithQueue.DbgConnectionId, 0, 0, 0, null, null, null, null, "The stub connection is constructed after exception."); connectionWithQueue.Remote.Renew(connectionWithQueue.CloseConnectionAfterInactivity, false); this._persistent.Set(tcpSocketInfo.PrimaryRemoteUri, tcpSocketInfo.ConnectionName, connectionWithQueue); // initiate connection reestablishing if (tcpSocketInfo.Remote.GenuinePersistentConnectionState == GenuinePersistentConnectionState.Opened) GenuineThreadPool.QueueUserWorkItem(new WaitCallback(this.ReestablishConnection), connectionWithQueue, true); } } else { // LOG: if ( binaryLogWriter != null && binaryLogWriter[LogCategory.Connection] > 0 ) binaryLogWriter.WriteEvent(LogCategory.Connection, "TcpConnectionManager.SocketFailed", LogMessageType.ConnectionReestablishing, exception, null, tcpSocketInfo.Remote, null, GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name, null, null, tcpSocketInfo.DbgConnectionId, 0, 0, 0, null, null, null, null, "The connection establishing has not been initiated since the original TcpSocketInfo is absent."); } } } catch(Exception ex) { // LOG: if ( binaryLogWriter != null && binaryLogWriter[LogCategory.Connection] > 0 ) binaryLogWriter.WriteEvent(LogCategory.Connection, "TcpConnectionManager.SocketFailed", LogMessageType.ConnectionReestablishing, ex, null, tcpSocketInfo == null ? null : tcpSocketInfo.Remote, null, GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name, null, null, tcpSocketInfo.DbgConnectionId, 0, 0, 0, null, null, null, null, "An exception is occurred while trying to initiate connection reestablishing."); // queue overloaded or fatal connection error // force connection closing this.SocketFailed(GenuineExceptions.Get_Receive_ConnectionClosed(), tcpSocketInfo); return ; } break; case GenuineConnectionType.Named: // update the pool string fullConnectionName = GetNamedConnectionName(tcpSocketInfo.IsServer, tcpSocketInfo.Remote, tcpSocketInfo.ConnectionName); lock (this._named) { if (object.ReferenceEquals(this._named[fullConnectionName], tcpSocketInfo)) this._named.Remove(fullConnectionName); } // release queue if (tcpSocketInfo.MessageContainer != null) tcpSocketInfo.MessageContainer.Dispose(exception); // release all of them if (exception is GenuineExceptions.ChannelClosed || exception is GenuineExceptions.ServerHasBeenRestarted) this.ITransportContext.KnownHosts.ReleaseHostResources(tcpSocketInfo.Remote, exception); break; case GenuineConnectionType.Invocation: lock (tcpSocketInfo) { switch (tcpSocketInfo.TcpInvocationFiniteAutomatonState) { case TcpInvocationFiniteAutomatonState.ClientAvailable: case TcpInvocationFiniteAutomatonState.ClientReceiving: case TcpInvocationFiniteAutomatonState.ClientSending: // break client state cycle according to FA transition diagram lock (this._invocation) { ArrayList connections = (ArrayList) this._invocation[tcpSocketInfo.Remote.Url]; if (connections != null) lock (connections) connections.Remove(tcpSocketInfo); } lock (tcpSocketInfo) { if (tcpSocketInfo.InitialMessage != null) if (tcpSocketInfo.InitialMessage.IsResendAfterFail && ! tcpSocketInfo.InitialMessage.IsSynchronous) { Message message = tcpSocketInfo.InitialMessage; tcpSocketInfo.InitialMessage = null; this.Send(message); } else { this.ITransportContext.IIncomingStreamHandler.DispatchException(tcpSocketInfo.InitialMessage, exception); tcpSocketInfo.InitialMessage = null; } } break; case TcpInvocationFiniteAutomatonState.ServerAwaiting: case TcpInvocationFiniteAutomatonState.ServerExecution: case TcpInvocationFiniteAutomatonState.ServerSending: lock (this._knownInvocationConnections.SyncRoot) this._knownInvocationConnections.Remove(tcpSocketInfo.ConnectionName); break; } } break; } // close the socket GenuineThreadPool.QueueUserWorkItem(new WaitCallback(LowLevel_CloseConnection), tcpSocketInfo, false); } catch(Exception ex) { // LOG: if ( binaryLogWriter != null ) binaryLogWriter.WriteImplementationWarningEvent("TcpConnectionManager.SocketFailed", LogMessageType.Warning, ex, GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name, "An unexpected exception is raised inside TcpConnectionManager.SocketFailed method. Most likely, something must be fixed."); } }
/// <summary> /// Sends a message synchronously. Does not process exceptions! /// </summary> /// <param name="message">Message.</param> /// <param name="tcpSocketInfo">Acquired connection.</param> public void LowLevel_SendSync(Message message, TcpSocketInfo tcpSocketInfo) { Stream stream = null; BinaryLogWriter binaryLogWriter = this.ITransportContext.BinaryLogWriter; // LOG: if ( binaryLogWriter != null && binaryLogWriter[LogCategory.Transport] > 0 ) binaryLogWriter.WriteEvent(LogCategory.Transport, "TcpConnectionManager.LowLevel_SendSync", LogMessageType.MessageIsSentSynchronously, null, message, message.Recipient, null, GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name, tcpSocketInfo.ConnectionLevelSecurity == null ? null : tcpSocketInfo.ConnectionLevelSecurity, tcpSocketInfo.ConnectionLevelSecurity == null ? null : tcpSocketInfo.ConnectionLevelSecurity.Name, tcpSocketInfo.DbgConnectionId, 0, 0, 0, null, null, null, null, "The connection has been obtained and the message is being sent synchronously."); try { // PING: prevent a ping if (tcpSocketInfo.GenuineConnectionType == GenuineConnectionType.Persistent) tcpSocketInfo.LastTimeContentWasSent = GenuineUtility.TickCount; tcpSocketInfo.SetupWriting(message.FinishTime); // create a stream bool finished = false; // enable connection-level security encryption stream = message.SerializedContent; if (tcpSocketInfo.ConnectionLevelSecurity != null) { GenuineChunkedStream encryptedContentStream = new GenuineChunkedStream(true); tcpSocketInfo.ConnectionLevelSecurity.Encrypt(stream, encryptedContentStream); stream = encryptedContentStream; } // send it in chunks while ( ! finished ) { int currentPosition = HEADER_SIZE; // read data int size = 0; while ( tcpSocketInfo._sendBuffer.Length > currentPosition && (size = stream.Read(tcpSocketInfo._sendBuffer, currentPosition, tcpSocketInfo._sendBuffer.Length - currentPosition)) > 0) { if (size <= 0) break; currentPosition += size; } finished = currentPosition < tcpSocketInfo._sendBuffer.Length; int totalSize = currentPosition; // prepare header tcpSocketInfo._sendBuffer[0] = MessageCoder.COMMAND_MAGIC_CODE; MessageCoder.WriteInt32(tcpSocketInfo._sendBuffer, 1, totalSize - HEADER_SIZE); tcpSocketInfo._sendBuffer[5] = finished ? (byte) 1 : (byte) 0; // and send it currentPosition = 0; tcpSocketInfo.Write(tcpSocketInfo._sendBuffer, currentPosition, totalSize); this.IncreaseBytesSent(totalSize); } // the message can be resent only if the persistent pattern is used if (tcpSocketInfo.GenuineConnectionType == GenuineConnectionType.Persistent && ! (bool) this.ITransportContext.IParameterProvider[GenuineParameter.TcpDoNotResendMessages]) tcpSocketInfo.MessagesSentSynchronously.PutMessage(message); } catch(Exception ex) { // LOG: if ( binaryLogWriter != null && binaryLogWriter[LogCategory.Transport] > 0 ) binaryLogWriter.WriteEvent(LogCategory.Transport, "TcpConnectionManager.LowLevel_SendSync", LogMessageType.MessageIsSentSynchronously, ex, message, message.Recipient, null, GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name, tcpSocketInfo.ConnectionLevelSecurity == null ? null : tcpSocketInfo.ConnectionLevelSecurity, tcpSocketInfo.ConnectionLevelSecurity == null ? null : tcpSocketInfo.ConnectionLevelSecurity.Name, tcpSocketInfo.DbgConnectionId, 0, 0, 0, null, null, null, null, "The exception occurred while synchronous sending."); throw; } finally { lock (tcpSocketInfo) tcpSocketInfo.LockForSending = false; } // the message was sent // PING: schedule a ping if (tcpSocketInfo.GenuineConnectionType == GenuineConnectionType.Persistent) tcpSocketInfo.LastTimeContentWasSent = GenuineUtility.TickCount; }
/// <summary> /// Sends the message to the remote host. /// Returns a response if corresponding Security Session is established and the initial message is not one-way. /// </summary> /// <param name="message">The message to be sent asynchronously.</param> /// <param name="tcpSocketInfo">The connection.</param> private void SendAsync(Message message, TcpSocketInfo tcpSocketInfo) { try { // try to acquire read access bool sendAccessGranted = true; lock (tcpSocketInfo) { if (tcpSocketInfo.LockForSending) { sendAccessGranted = false; tcpSocketInfo.MessageContainer.AddMessage(message, false); } else tcpSocketInfo.LockForSending = true; } if (sendAccessGranted) { tcpSocketInfo.Message = message; tcpSocketInfo.AsyncSendStream = null; // LOG: BinaryLogWriter binaryLogWriter = this.ITransportContext.BinaryLogWriter; if ( binaryLogWriter != null && binaryLogWriter[LogCategory.Transport] > 0 ) binaryLogWriter.WriteEvent(LogCategory.Transport, "TcpConnectionManager.SendAsync", LogMessageType.MessageIsSentAsynchronously, null, message, message.Recipient, null, GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name, tcpSocketInfo.ConnectionLevelSecurity == null ? null : tcpSocketInfo.ConnectionLevelSecurity, tcpSocketInfo.ConnectionLevelSecurity == null ? null : tcpSocketInfo.ConnectionLevelSecurity.Name, tcpSocketInfo.DbgConnectionId, 0, 0, 0, null, null, null, null, "The connection has been obtained and the message is being sent asynchronously."); LowLevel_StartSending(message, tcpSocketInfo); } } catch(Exception ex) { this.SocketFailed(ex, tcpSocketInfo); } }
/// <summary> /// Sends the message to the remote host. /// Returns a response if corresponding Security Session parameters are set and /// the initial message is not one-way. /// </summary> /// <param name="message">Message to be sent synchronously.</param> /// <param name="tcpSocketInfo">Socket connection.</param> private void SendSync(Message message, TcpSocketInfo tcpSocketInfo) { SyncMessageSlot syncMessageSlot = null; // try to acquire the read access bool sendAccessGranted = true; lock (tcpSocketInfo) { if (tcpSocketInfo.LockForSending) { // wait until the current sending finishes syncMessageSlot = new SyncMessageSlot(); tcpSocketInfo.MessageContainer.AddMessage(syncMessageSlot, false); sendAccessGranted = false; } else tcpSocketInfo.LockForSending = true; } if (! sendAccessGranted) { // allow SyncSinkStackProcess to influence on the message processing WaitHandle[] waitHandles = null; if (message.CancelSending != null) { waitHandles = new WaitHandle[2]; waitHandles[1] = message.CancelSending; } else waitHandles = new WaitHandle[1]; waitHandles[0] = syncMessageSlot.ConnectionAvailable; // wait for any of events int milliseconds = GenuineUtility.GetMillisecondsLeft(message.FinishTime); if (milliseconds <= 0) throw GenuineExceptions.Get_Send_ServerDidNotReply(); int resultFlag = WaitHandle.WaitAny(waitHandles, milliseconds, false); if ( resultFlag == WaitHandle.WaitTimeout ) { lock (syncMessageSlot) { syncMessageSlot.IsValid = false; // initiate sending of the next message if (syncMessageSlot.TcpSocketInfo != null) this.Pool_StartSending(syncMessageSlot.TcpSocketInfo); } throw GenuineExceptions.Get_Send_ServerDidNotReply(); } if (resultFlag == 1) throw GenuineExceptions.Get_Send_Timeout(); // rethrow the exception if (syncMessageSlot.SyncWaitException != null) throw OperationException.WrapException(syncMessageSlot.SyncWaitException); tcpSocketInfo = syncMessageSlot.TcpSocketInfo; } // send it this.LowLevel_SendSync(message, tcpSocketInfo); switch(tcpSocketInfo.GenuineConnectionType) { case GenuineConnectionType.Persistent: case GenuineConnectionType.Named: message.IsResendAfterFail = false; this.Pool_StartSending(tcpSocketInfo); break; case GenuineConnectionType.Invocation: // it's necessary to provide correct infomation, de bene esse lock (tcpSocketInfo) { tcpSocketInfo.TcpInvocationFiniteAutomatonState = TcpInvocationFiniteAutomatonState.ClientReceiving; tcpSocketInfo.Renew(); } // if (! tcpSocketInfo.IsServer && ! message.IsOneWay) // { // // read the response // using (Stream stream = this.LowLevel_ReadSync(tcpSocketInfo, message.FinishTime)) // this.ITransportContext.IIncomingStreamHandler.HandleMessage(stream, tcpSocketInfo.Remote, tcpSocketInfo.GenuineConnectionType, tcpSocketInfo.ConnectionName, true, null, tcpSocketInfo.ConnectionLevelSecurity, null); // } lock (tcpSocketInfo) { tcpSocketInfo.TcpInvocationFiniteAutomatonState = TcpInvocationFiniteAutomatonState.ClientAvailable; tcpSocketInfo.Renew(); } break; } }
/// <summary> /// Initiates reading incoming content from the socket and dispatching it to the message handler manager. /// Should be called only once for persistent and named connections. /// </summary> /// <param name="tcpSocketInfo">The connection.</param> /// <param name="iParameterProvider">Parameter provider or a null reference.</param> private void Pool_InitiateReceiving(TcpSocketInfo tcpSocketInfo, IParameterProvider iParameterProvider) { this.LowLevel_HalfSync_StartReceiving(tcpSocketInfo); }
/// <summary> /// Assigns the sending task for a connection. /// </summary> /// <param name="tcpSocketInfo">Tcp connection.</param> private void Pool_StartSending(TcpSocketInfo tcpSocketInfo) { Message message = null; switch (tcpSocketInfo.GenuineConnectionType) { case GenuineConnectionType.Persistent: case GenuineConnectionType.Named: lock (tcpSocketInfo) { // if something uses this socket if (tcpSocketInfo.LockForSending) return ; tcpSocketInfo.LockForSending = true; // try to send the next item in the queue for ( ; ; ) { message = (Message) tcpSocketInfo.MessageContainer.GetMessage(); if (message == null) { tcpSocketInfo.LockForSending = false; return ; } if (message is SyncMessageSlot) { SyncMessageSlot syncMessageSlot = (SyncMessageSlot) message; lock (syncMessageSlot) { if (! syncMessageSlot.IsValid) continue; syncMessageSlot.TcpSocketInfo = tcpSocketInfo; syncMessageSlot.ConnectionAvailable.Set(); break; } } // LOG: BinaryLogWriter binaryLogWriter = this.ITransportContext.BinaryLogWriter; if ( binaryLogWriter != null && binaryLogWriter[LogCategory.Transport] > 0 ) binaryLogWriter.WriteEvent(LogCategory.Transport, "TcpConnectionManager.SendAsync", LogMessageType.MessageIsSentAsynchronously, null, message, message.Recipient, null, GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name, tcpSocketInfo.ConnectionLevelSecurity == null ? null : tcpSocketInfo.ConnectionLevelSecurity, tcpSocketInfo.ConnectionLevelSecurity == null ? null : tcpSocketInfo.ConnectionLevelSecurity.Name, tcpSocketInfo.DbgConnectionId, 0, 0, 0, null, null, null, null, "The connection has been obtained and the message is being sent asynchronously."); tcpSocketInfo.Message = message; tcpSocketInfo.AsyncSendStream = null; this.LowLevel_StartSending(message, tcpSocketInfo); break; } } break; case GenuineConnectionType.Invocation: this.Pool_HandleAvailableInvocationOrOneWayConnection(tcpSocketInfo); break; } }
/// <summary> /// Sets correct connection state and parameters when the current operation is successfully completed. /// </summary> /// <param name="tcpSocketInfo"></param> private void Pool_HandleAvailableInvocationOrOneWayConnection(TcpSocketInfo tcpSocketInfo) { if (tcpSocketInfo.CloseConnectionAfterInactivity <= 0) this.SocketFailed(GenuineExceptions.Get_Connection_LifetimeCycleEnded(), tcpSocketInfo); else tcpSocketInfo.Renew(); }
/// <summary> /// Destroys the specified connection and releases absolutely all resources belonging to /// the remote host the connection points at. /// </summary> /// <param name="tcpSocketInfo">The connection.</param> /// <param name="reason">The reason of disposing connection resources.</param> private void Pool_DestroyPersistentConnection(TcpSocketInfo tcpSocketInfo, Exception reason) { bool disposeMessages = false; bool connectionAvailable = true; // the queue lock (this._persistent.SyncRoot) { TcpSocketInfo currentTcpSocketInfo = this._persistent.Get(tcpSocketInfo.PrimaryRemoteUri, tcpSocketInfo.ConnectionName) as TcpSocketInfo; // if it's still the stub if (object.ReferenceEquals(currentTcpSocketInfo, tcpSocketInfo)) { this._persistent.Remove(tcpSocketInfo.PrimaryRemoteUri, tcpSocketInfo.ConnectionName); connectionAvailable = this._persistent.Get(tcpSocketInfo.PrimaryRemoteUri, null) != null; disposeMessages = true; } } // release messages if (disposeMessages) tcpSocketInfo.MessageContainer.Dispose(reason); // release HostInformation if there are no connections available if (! connectionAvailable) { tcpSocketInfo.SignalState(GenuineEventType.GeneralConnectionClosed, reason, null); this.ITransportContext.KnownHosts.ReleaseHostResources(tcpSocketInfo.Remote, reason); } GenuineThreadPool.QueueUserWorkItem(new WaitCallback(LowLevel_CloseConnection), tcpSocketInfo, false); }
/// <summary> /// Starts sending the message through the specified connection. /// </summary> /// <param name="message">The message being sent.</param> /// <param name="tcpSocketInfo">The connection.</param> private void LowLevel_StartSending(Message message, TcpSocketInfo tcpSocketInfo) { // PING: prevent the ping if (tcpSocketInfo.GenuineConnectionType == GenuineConnectionType.Persistent) tcpSocketInfo.LastTimeContentWasSent = GenuineUtility.TickCount; if (tcpSocketInfo.AsyncSendStream == null) { tcpSocketInfo.AsyncSendStream = message.SerializedContent; if (tcpSocketInfo.ConnectionLevelSecurity != null && message.SerializedContent != Stream.Null) { GenuineChunkedStream encryptedContentStream = new GenuineChunkedStream(true); tcpSocketInfo.ConnectionLevelSecurity.Encrypt(tcpSocketInfo.AsyncSendStream, encryptedContentStream); tcpSocketInfo.AsyncSendStream = encryptedContentStream; } } // initiate the sending tcpSocketInfo.Message = message; if (tcpSocketInfo.AsyncSendBuffer == null) tcpSocketInfo.AsyncSendBuffer = new byte[tcpSocketInfo.MaxSendSize]; tcpSocketInfo.AsyncSendBufferCurrentPosition = 0; tcpSocketInfo.AsyncSendBufferSizeOfValidContent = HEADER_SIZE + GenuineUtility.TryToReadFromStream(tcpSocketInfo.AsyncSendStream, tcpSocketInfo.AsyncSendBuffer, HEADER_SIZE, tcpSocketInfo.AsyncSendBuffer.Length - HEADER_SIZE); tcpSocketInfo.AsyncSendBuffer[0] = MessageCoder.COMMAND_MAGIC_CODE; MessageCoder.WriteInt32(tcpSocketInfo.AsyncSendBuffer, 1, tcpSocketInfo.AsyncSendBufferSizeOfValidContent - HEADER_SIZE); tcpSocketInfo.AsyncSendBufferIsLastPacket = tcpSocketInfo.AsyncSendBufferSizeOfValidContent < tcpSocketInfo.AsyncSendBuffer.Length - HEADER_SIZE; tcpSocketInfo.AsyncSendBuffer[5] = tcpSocketInfo.AsyncSendBufferIsLastPacket ? (byte) 1 : (byte) 0; // LOG: BinaryLogWriter binaryLogWriter = this.ITransportContext.BinaryLogWriter; if ( binaryLogWriter != null && binaryLogWriter[LogCategory.Transport] > 0 ) { binaryLogWriter.WriteTransportContentEvent(LogCategory.Transport, "TcpConnectionManager.LowLevel_StartSending", LogMessageType.AsynchronousSendingStarted, null, tcpSocketInfo.Message, tcpSocketInfo.Remote, binaryLogWriter[LogCategory.Transport] > 1 ? new MemoryStream(GenuineUtility.CutOutBuffer(tcpSocketInfo.AsyncSendBuffer, tcpSocketInfo.AsyncSendBufferCurrentPosition, tcpSocketInfo.AsyncSendBufferSizeOfValidContent - tcpSocketInfo.AsyncSendBufferCurrentPosition)) : null, GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name, tcpSocketInfo.DbgConnectionId, tcpSocketInfo.AsyncSendBufferSizeOfValidContent - tcpSocketInfo.AsyncSendBufferCurrentPosition, tcpSocketInfo.Remote.PhysicalAddress.ToString(), null, null, "The chunk is being sent asynchronously."); } AsyncThreadStarter.QueueTask(new Async_InitiateSocketSending(tcpSocketInfo.Socket, tcpSocketInfo.AsyncSendBuffer, tcpSocketInfo.AsyncSendBufferCurrentPosition, tcpSocketInfo.AsyncSendBufferSizeOfValidContent - tcpSocketInfo.AsyncSendBufferCurrentPosition, this._onEndSending, tcpSocketInfo)); // tcpSocketInfo.Socket.BeginSend(tcpSocketInfo.AsyncSendBuffer, tcpSocketInfo.AsyncSendBufferCurrentPosition, tcpSocketInfo.AsyncSendBufferSizeOfValidContent - tcpSocketInfo.AsyncSendBufferCurrentPosition, SocketFlags.None, this._onEndSending, tcpSocketInfo); }
/// <summary> /// Provides a stream reading synchronously from the given connection. /// </summary> /// <param name="tcpSocketInfo">Socket structure.</param> /// <param name="timeoutInMilliseconds">Read timeout.</param> /// <param name="automaticallyContinueReading">Indicates whether this instance will automatically initiate reading of the next message from the specified connection.</param> /// <returns>A stream.</returns> private Stream LowLevel_ReadSync(TcpSocketInfo tcpSocketInfo, int timeoutInMilliseconds, bool automaticallyContinueReading) { Stream inputStream = new SyncSocketReadingStream(this, tcpSocketInfo, timeoutInMilliseconds, automaticallyContinueReading); if (tcpSocketInfo.ConnectionLevelSecurity != null) return tcpSocketInfo.ConnectionLevelSecurity.Decrypt(inputStream); return inputStream; }
/// <summary> /// Acquires a connection according to message parameters or throw the corresponding exception /// if it's impossible. /// </summary> /// <param name="message">The message being sent.</param> /// <returns>The acquired connection.</returns> private TcpSocketInfo GetConnectionForSending(Message message) { BinaryLogWriter binaryLogWriter = this.ITransportContext.BinaryLogWriter; TcpSocketInfo tcpSocketInfo = null; string uri = null; bool isServer = false; string remoteUri = null; int remoteHostUniqueIdentifier; using (new ReaderAutoLocker(this._disposeLock)) { if (this._disposed) throw OperationException.WrapException(this._disposeReason); switch (message.SecuritySessionParameters.GenuineConnectionType) { case GenuineConnectionType.Persistent: uri = message.Recipient.Url; if (message.ConnectionName == null) message.ConnectionName = message.SecuritySessionParameters.ConnectionName; lock (message.Recipient.PersistentConnectionEstablishingLock) { switch (message.Recipient.GenuinePersistentConnectionState) { case GenuinePersistentConnectionState.NotEstablished: if (message.Recipient.Url == null) throw GenuineExceptions.Get_Send_DestinationIsUnreachable(message.Recipient.Uri); message.Recipient.GenuinePersistentConnectionState = GenuinePersistentConnectionState.Opened; break; case GenuinePersistentConnectionState.Accepted: isServer = true; uri = message.Recipient.Uri; break; } // if it's possible to establish a connection to the remote host if (! isServer) { tcpSocketInfo = this._persistent.Get(uri, message.ConnectionName) as TcpSocketInfo; if (tcpSocketInfo != null && !tcpSocketInfo.IsValid) { this._persistent.Remove(uri, message.ConnectionName); tcpSocketInfo = null; } if (tcpSocketInfo == null) { // try to establish a persistent connection tcpSocketInfo = LowLevel_OpenConnection(message.Recipient, GenuineConnectionType.Persistent, this.Local.Uri, this.LocalPort, message.ConnectionName, out remoteUri, out remoteHostUniqueIdentifier); // update remote host info message.Recipient.UpdateUri(remoteUri, remoteHostUniqueIdentifier); message.Recipient.PhysicalAddress = tcpSocketInfo.Socket.RemoteEndPoint; message.Recipient.LocalPhysicalAddress = tcpSocketInfo.Socket.LocalEndPoint; tcpSocketInfo.Remote = message.Recipient; // LOG: if ( binaryLogWriter != null && binaryLogWriter[LogCategory.HostInformation] > 0 ) { binaryLogWriter.WriteHostInformationEvent("TcpConnectionManager.LowLevel_OpenConnection", LogMessageType.HostInformationCreated, null, message.Recipient, GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name, tcpSocketInfo.ConnectionLevelSecurity, tcpSocketInfo.ConnectionLevelSecurity == null ? null : tcpSocketInfo.ConnectionLevelSecurity.Name, tcpSocketInfo.DbgConnectionId, "HostInformation is ready for actions."); } // OK, connection established tcpSocketInfo.MessageContainer = new MessageContainer(this.ITransportContext); this._persistent.Set(uri, tcpSocketInfo.ConnectionName, tcpSocketInfo); tcpSocketInfo.CloseConnectionAfterInactivity = GenuineUtility.ConvertToMilliseconds(this.ITransportContext.IParameterProvider[GenuineParameter.ClosePersistentConnectionAfterInactivity]); tcpSocketInfo.Renew(); tcpSocketInfo.SignalState(GenuineEventType.GeneralConnectionEstablished, null, null); // LOG: if ( binaryLogWriter != null && binaryLogWriter[LogCategory.Connection] > 0 ) { binaryLogWriter.WriteEvent(LogCategory.Connection, "TcpConnectionManager.GetConnectionForSending", LogMessageType.ConnectionEstablished, null, null, tcpSocketInfo.Remote, null, GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name, tcpSocketInfo.ConnectionLevelSecurity, tcpSocketInfo.ConnectionLevelSecurity == null ? null : tcpSocketInfo.ConnectionLevelSecurity.Name, tcpSocketInfo.DbgConnectionId, (int) message.SecuritySessionParameters.GenuineConnectionType, 0, 0, this.GetType().Name, message.Recipient.LocalPhysicalAddress.ToString(), message.Recipient.PhysicalAddress.ToString(), null, "The connection to the remote host is established."); } this.Pool_StartSending(tcpSocketInfo); this.Pool_InitiateReceiving(tcpSocketInfo, this.ITransportContext.IParameterProvider); } } else { // remote host is a client and if there is no connection to it, it's unreachable tcpSocketInfo = this._persistent.Get(uri, message.ConnectionName) as TcpSocketInfo; if (tcpSocketInfo == null) throw GenuineExceptions.Get_Send_DestinationIsUnreachable(message.Recipient.Uri); } } break; case GenuineConnectionType.Named: if (message.ConnectionName == null) message.ConnectionName = message.SecuritySessionParameters.ConnectionName; isServer = message.Recipient.Url == null; string fullConnectionName = this.GetNamedConnectionName(isServer, message.Recipient, message.ConnectionName); try { // if it's possible to establish a connection to the remote host if (! isServer) { bool shouldBeEstablished = false; lock (this._named) { tcpSocketInfo = this._named[fullConnectionName] as TcpSocketInfo; // if it's necessary to establish a connection if (tcpSocketInfo == null) { shouldBeEstablished = true; // register a message queue for this connection tcpSocketInfo = new TcpSocketInfo(null, this.ITransportContext, message.ConnectionName #if DEBUG ,"Stub for the named connection while it's being established." #endif ); tcpSocketInfo.Remote = message.Recipient; tcpSocketInfo.GenuineConnectionType = GenuineConnectionType.Named; tcpSocketInfo.LockForSending = true; tcpSocketInfo.CloseConnectionAfterInactivity = GenuineUtility.ConvertToMilliseconds(this.ITransportContext.IParameterProvider[GenuineParameter.ConnectTimeout]); tcpSocketInfo.MessageContainer = new MessageContainer(this.ITransportContext); tcpSocketInfo.Renew(); this._named[fullConnectionName] = tcpSocketInfo; } } if (shouldBeEstablished) { // try to establish named connection tcpSocketInfo = LowLevel_OpenConnection(message.Recipient, GenuineConnectionType.Named, this.Local.Uri, this.LocalPort, message.ConnectionName, out remoteUri, out remoteHostUniqueIdentifier); // update remote host info message.Recipient.UpdateUri(remoteUri, remoteHostUniqueIdentifier); message.Recipient.PhysicalAddress = tcpSocketInfo.Socket.RemoteEndPoint; message.Recipient.LocalPhysicalAddress = tcpSocketInfo.Socket.LocalEndPoint; tcpSocketInfo.Remote = message.Recipient; // calculate the time to close the connection after if (message.SecuritySessionParameters.CloseAfterInactivity == TimeSpan.MinValue) tcpSocketInfo.CloseConnectionAfterInactivity = GenuineUtility.ConvertToMilliseconds(this.ITransportContext.IParameterProvider[GenuineParameter.CloseNamedConnectionAfterInactivity]); else tcpSocketInfo.CloseConnectionAfterInactivity = GenuineUtility.ConvertToMilliseconds(message.SecuritySessionParameters.CloseAfterInactivity); tcpSocketInfo.Renew(); // and exchange it with the registered queue lock (this._named) { TcpSocketInfo stubWithQueue = (TcpSocketInfo) this._named[fullConnectionName]; this._named[fullConnectionName] = tcpSocketInfo; tcpSocketInfo.MessageContainer = stubWithQueue.MessageContainer; } // LOG: if ( binaryLogWriter != null && binaryLogWriter[LogCategory.Connection] > 0 ) { binaryLogWriter.WriteEvent(LogCategory.Connection, "TcpConnectionManager.GetConnectionForSending", LogMessageType.ConnectionEstablished, null, null, tcpSocketInfo.Remote, null, GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name, tcpSocketInfo.ConnectionLevelSecurity, tcpSocketInfo.ConnectionLevelSecurity == null ? null : tcpSocketInfo.ConnectionLevelSecurity.Name, tcpSocketInfo.DbgConnectionId, (int) message.SecuritySessionParameters.GenuineConnectionType, 0, 0, this.GetType().Name, message.Recipient.LocalPhysicalAddress.ToString(), message.Recipient.PhysicalAddress.ToString(), null, "The connection to the remote host is established."); } this.Pool_StartSending(tcpSocketInfo); this.Pool_InitiateReceiving(tcpSocketInfo, this.ITransportContext.IParameterProvider); } } else { // remote host is a client and if there are no connection to it, it's unreachable lock (this._named) tcpSocketInfo = this._named[fullConnectionName] as TcpSocketInfo; if (tcpSocketInfo == null) { Exception exception = GenuineExceptions.Get_Send_DestinationIsUnreachable(message.Recipient.Uri); // LOG: if ( binaryLogWriter != null && binaryLogWriter[LogCategory.Connection] > 0 ) { binaryLogWriter.WriteEvent(LogCategory.Connection, "TcpConnectionManager.GetConnectionForSending", LogMessageType.ConnectionEstablished, exception, message, message.Recipient, null, GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name, null, null, -1, (int) message.SecuritySessionParameters.GenuineConnectionType, 0, 0, this.GetType().Name, null, null, null, "The connection to the remote host cannot be established."); } throw exception; } } } catch(Exception ex) { tcpSocketInfo.Remote = message.Recipient; this.SocketFailed(ex, tcpSocketInfo); TcpSocketInfo existingConnection = null; lock (this._named) existingConnection = this._named[fullConnectionName] as TcpSocketInfo; this.SocketFailed(ex, existingConnection); // // MessageContainer messageContainerToBeClearedUp = null; // lock (this._named) // { // TcpSocketInfo existingConnection = this._named[fullConnectionName] as TcpSocketInfo; // if (existingConnection != null) // messageContainerToBeClearedUp = existingConnection.MessageContainer; // this._named.Remove(fullConnectionName); // } // // if (messageContainerToBeClearedUp != null) // messageContainerToBeClearedUp.Dispose(ex); // // if (ConnectionManager.IsExceptionCritical(ex as OperationException)) // message.Recipient.Dispose(ex); throw; } break; case GenuineConnectionType.Invocation: // TODO: remove it after updating this code throw new ApplicationException("This version of Genuine Channels does not support the Invocation Connection Pattern."); // // if it's a request, it's necessary to open the connection // if (message.ConnectionId == null || ! message.ConnectionId.StartsWith("~")) // { // // try to find inactive one // ArrayList invocationConnections = null; // lock (this._invocationConnections.SyncRoot) // { // invocationConnections = this._invocationConnections[message.Recipient.Url] as ArrayList; // if (invocationConnections == null) // this._invocationConnections[message.Recipient.Url] = invocationConnections = new ArrayList(); // } // // lock (invocationConnections) // for ( int i = 0; i < invocationConnections.Count ; i++ ) // { // tcpSocketInfo = (TcpSocketInfo) invocationConnections[i]; // if (tcpSocketInfo.IsValid && tcpSocketInfo.TcpInvocationFiniteAutomatonState == TcpInvocationFiniteAutomatonState.ClientAvailable) // { // // connection may be broken // message.IsResendAfterFail = true; // tcpSocketInfo.TcpInvocationFiniteAutomatonState = TcpInvocationFiniteAutomatonState.ClientSending; // tcpSocketInfo.InitialMessage = message; // break; // } // else // tcpSocketInfo = null; // } // // if (tcpSocketInfo == null) // { // // it is necessary to open a new one // tcpSocketInfo = LowLevel_OpenConnection(message.Recipient, GenuineConnectionType.Invocation, this.Local.Uri, this.LocalPort, null, out remoteUri); // tcpSocketInfo.Remote = message.Recipient; // // // update remote host info // message.Recipient.UpdateUri(remoteUri); // tcpSocketInfo.Remote = message.Recipient; // tcpSocketInfo.TcpInvocationFiniteAutomatonState = TcpInvocationFiniteAutomatonState.ClientSending; // tcpSocketInfo.InitialMessage = message; // message.IsResendAfterFail = false; // // // calculate the time to close the connection after // if (message.SecuritySessionParameters.CloseAfterInactivity == TimeSpan.MinValue) // tcpSocketInfo.CloseConnectionAfterInactivity = GenuineUtility.ConvertToMilliseconds(this.ITransportContext.IParameterProvider[GenuineParameter.CloseInvocationConnectionAfterInactivity]); // else // tcpSocketInfo.CloseConnectionAfterInactivity = GenuineUtility.ConvertToMilliseconds(message.SecuritySessionParameters.CloseAfterInactivity); // tcpSocketInfo.Renew(); // // // add opened connection to connection pool // lock (this._invocationConnections.SyncRoot) // { // ArrayList connections = (ArrayList) this._invocationConnections[message.Recipient.Url]; // lock (connections) // connections.Add(tcpSocketInfo); // } // // this.Pool_InitiateReceiving(tcpSocketInfo, this.ITransportContext.IParameterProvider); // } // } // else // { // // it's a reply, it's necessary just to send the response through // // the existent connection with the given name // tcpSocketInfo = this._knownInvocationConnections[message.ConnectionId] as TcpSocketInfo; // if (tcpSocketInfo == null) // throw GenuineExceptions.Get_Send_NoNamedConnectionFound(message.ConnectionId); // tcpSocketInfo.TcpInvocationFiniteAutomatonState = TcpInvocationFiniteAutomatonState.ServerSending; // tcpSocketInfo.InitialMessage = message; // } // // tcpSocketInfo.Renew(); // break; default: throw GenuineExceptions.Get_Connect_CanNotConnectToRemoteHost(message.Recipient.PrimaryUri, "Invalid type of connection requested."); } } return tcpSocketInfo; }