/// <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>
        /// 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;
        }