/// <summary>
        /// Initiates the listening request.
        /// </summary>
        /// <param name="httpClientConnection">The connection.</param>
        /// <param name="requestNextPacket">Whether to request the next packet.</param>
        private void LowLevel_InitiateListening(HttpClientConnection httpClientConnection, bool requestNextPacket)
        {
            BinaryLogWriter binaryLogWriter = this.ITransportContext.BinaryLogWriter;

            try
            {
            #if DEBUG
                Debug.Assert(httpClientConnection.GenuineConnectionType == GenuineConnectionType.Persistent);
            #endif

                if (requestNextPacket)
                    httpClientConnection.ListenerSequenceNo ++;

                // write the request header
                using (GenuineChunkedStream listenerStream = new GenuineChunkedStream(false))
                {
                    BinaryWriter binaryWriter = new BinaryWriter(listenerStream);
                    HttpMessageCoder.WriteRequestHeader(binaryWriter, MessageCoder.PROTOCOL_VERSION, httpClientConnection.GenuineConnectionType, httpClientConnection.HostId, HttpPacketType.Listening, httpClientConnection.ListenerSequenceNo, httpClientConnection.ConnectionName, httpClientConnection.Remote.LocalHostUniqueIdentifier);

                    // start the request
                    httpClientConnection.Listener = httpClientConnection.InitializeRequest(false, httpClientConnection._keepalive);
                    httpClientConnection.Listener.ContentLength = listenerStream.Length;

                    this.LowLevel_InitiateHttpWebRequest(httpClientConnection.Listener, listenerStream, httpClientConnection.ListenerClosed, false, httpClientConnection.OnEndReceiving, httpClientConnection);
                }
            }
            catch(Exception ex)
            {
                // It's necessary to schedule connection reestablishing

                // LOG:
                if ( binaryLogWriter != null && binaryLogWriter[LogCategory.Connection] > 0 )
                {
                    binaryLogWriter.WriteEvent(LogCategory.Connection, "HttpClientConnectionManager.LowLevel_InitiateListening",
                        LogMessageType.ConnectionFailed, ex, null, httpClientConnection.Remote, null,
                        GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name, null, null,
                        httpClientConnection.DbgConnectionId, 0, 0, 0, null, null, null, null,
                        "The LISTENER request Seq No={0} has failed. The connection will be reestablished, if possible.", httpClientConnection.ListenerSequenceNo);
                }

                this.StartReestablishingIfNecessary(httpClientConnection, ex, false);
            }
        }
        /// <summary>
        /// Opens connection to the remote host.
        /// </summary>
        /// <param name="remote">The remote host.</param>
        /// <param name="genuineConnectionType">The type of the connection.</param>
        /// <param name="connectionName">The name of the connection.</param>
        /// <returns>The opened connection.</returns>
        private HttpClientConnection LowLevel_OpenConnection(HostInformation remote, GenuineConnectionType genuineConnectionType, string connectionName)
        {
            BinaryLogWriter binaryLogWriter = this.ITransportContext.BinaryLogWriter;

            using (new ReaderAutoLocker(this._disposeLock))
            {
                if (this._disposed)
                    throw OperationException.WrapException(this._disposeReason);
            }

            // the time we should finish connection establishing before
            int timeout = GenuineUtility.GetTimeout((TimeSpan) this.ITransportContext.IParameterProvider[GenuineParameter.ConnectTimeout]);

            // LOG:
            if ( binaryLogWriter != null && binaryLogWriter[LogCategory.Connection] > 0 )
            {
                binaryLogWriter.WriteEvent(LogCategory.Connection, "HttpClientConnectionManager.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}\".", remote == null ? "?" : remote.Url == null ? "?" : remote.Url);
            }

            // first - send the check request and start CLSSE
            HttpClientConnection httpClientConnection = new HttpClientConnection(this.ITransportContext, connectionName);
            httpClientConnection.Remote = remote;
            httpClientConnection.GenuineConnectionType = genuineConnectionType;

            httpClientConnection.Sender_ConnectionLevelSecurity = this.CreateConnectionLevelSecuritySession(genuineConnectionType);
            httpClientConnection.Listener_ConnectionLevelSecurity = this.CreateConnectionLevelSecuritySession(genuineConnectionType);

            // LOG:
            if ( binaryLogWriter != null && binaryLogWriter[LogCategory.Connection] > 0 )
            {
                binaryLogWriter.WriteConnectionParameterEvent(LogCategory.Connection, "HttpClientConnectionManager.LowLevel_OpenConnection",
                    LogMessageType.ConnectionParameters, null, remote, this.ITransportContext.IParameterProvider,
                    GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name, httpClientConnection.DbgConnectionId,
                    "An HTTP connection is being established.");
            }

            // gather the output stream
            Stream senderInputClsseStream = Stream.Null;
            Stream listenerInputClsseStream = Stream.Null;
            Stream clsseStream = null;
            GenuineChunkedStream outputStream = null;
            bool resend = false;
            bool firstFailure = false;

            // CLSS establishing
            for ( int i = 0; ; i++ )
            {
                bool noClsseToSend = true;

                if (! resend)
                {
                    // build the content
                    outputStream = new GenuineChunkedStream(false);
                    BinaryWriter binaryWriter = new BinaryWriter(outputStream);
                    HttpMessageCoder.WriteRequestHeader(binaryWriter, MessageCoder.PROTOCOL_VERSION, genuineConnectionType, httpClientConnection.HostId,
                        i == 0 ? HttpPacketType.Establishing_ResetConnection : HttpPacketType.Establishing, ++httpClientConnection.SendSequenceNo,
                        httpClientConnection.ConnectionName, remote.LocalHostUniqueIdentifier);

                    // CLSSE info
                    using (new GenuineChunkedStreamSizeLabel(outputStream))
                    {
                        if (httpClientConnection.Sender_ConnectionLevelSecurity != null && ! httpClientConnection.Sender_ConnectionLevelSecurity.IsEstablished)
                        {
                            clsseStream = httpClientConnection.Sender_ConnectionLevelSecurity.EstablishSession(senderInputClsseStream, true);
                            if (clsseStream != null)
                            {
                                noClsseToSend = false;
                                GenuineUtility.CopyStreamToStream(clsseStream, outputStream);
                            }
                        }

                    }

                    // CLSSE info
                    using (new GenuineChunkedStreamSizeLabel(outputStream))
                    {
                        if (httpClientConnection.Listener_ConnectionLevelSecurity != null && ! httpClientConnection.Listener_ConnectionLevelSecurity.IsEstablished)
                        {
                            clsseStream = httpClientConnection.Listener_ConnectionLevelSecurity.EstablishSession(listenerInputClsseStream, true);
                            if (clsseStream != null)
                            {
                                noClsseToSend = false;
                                GenuineUtility.CopyStreamToStream(clsseStream, outputStream);
                            }
                        }
                    }
                }
                else
                    outputStream.Position = 0;

                // parse the response
                HttpWebRequest httpWebRequest = httpClientConnection.InitializeRequest(true, httpClientConnection._keepalive);
                int millisecondsRemain = GenuineUtility.CompareTickCounts(timeout, GenuineUtility.TickCount);
                if ( millisecondsRemain <= 0)
                    throw GenuineExceptions.Get_Channel_ConnectionClosedAfterTimeout();

                httpWebRequest.Timeout = millisecondsRemain;
                httpWebRequest.ContentLength = outputStream.Length;
                Stream requestStream = null;

                try
                {
                    requestStream = httpWebRequest.GetRequestStream();
                    GenuineUtility.CopyStreamToStream(outputStream, requestStream, (int) outputStream.Length);
                    using (HttpWebResponse httpWebResponse = (HttpWebResponse) httpWebRequest.GetResponse())
                    {
                        // LOG:
                        if ( binaryLogWriter != null && binaryLogWriter[LogCategory.Connection] > 0 )
                        {
                            StringBuilder stringBuilderHeaders = new StringBuilder(1024);
                            foreach (string headerName in httpWebResponse.Headers.Keys)
                                stringBuilderHeaders.AppendFormat("{0}=\"{1}\"; ", headerName, httpWebResponse.Headers.Get(headerName));

                            binaryLogWriter.WriteEvent(LogCategory.Connection, "HttpClientConnectionManager.LowLevel_OpenConnection",
                                LogMessageType.ConnectionEstablishing, null, null, remote, null,
                                GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name, null, null,
                                httpClientConnection.DbgConnectionId, 0, 0, 0, null, null, null, null,
                                "The trial connection has been successfully completed. Content-Length: {0}; Content encoding: {1}; Content type: {2}; Protocol version: {3}; Respose uri: {4}; Status code: {5}; Status description: {6}; HTTP headers: {7}.",
                                httpWebResponse.ContentLength, httpWebResponse.ContentEncoding, httpWebResponse.ContentType,
                                httpWebResponse.ProtocolVersion, httpWebResponse.ResponseUri,
                                httpWebResponse.StatusCode, httpWebResponse.StatusDescription,
                                stringBuilderHeaders.ToString());
                        }

                        using (Stream responseStream = httpWebResponse.GetResponseStream())
                        {
                            BinaryReader binaryReader = new BinaryReader(responseStream);
                            string serverUri;
                            int sequenceNo;
                            HttpPacketType httpPacketType;
                            int remoteHostUniqueIdentifier;

                            HttpMessageCoder.ReadResponseHeader(binaryReader, out serverUri, out sequenceNo, out httpPacketType, out remoteHostUniqueIdentifier);

                            if ( httpPacketType != HttpPacketType.Establishing && httpPacketType != HttpPacketType.Establishing_ResetConnection )
                                throw GenuineExceptions.Get_Connect_CanNotConnectToRemoteHost(remote.ToString(), "Wrong response received from the remote host.");

                            // check the restartion if either CLSS or the persistent connection is used
                            if (genuineConnectionType == GenuineConnectionType.Persistent || httpClientConnection.Sender_ConnectionLevelSecurity != null)
                                remote.UpdateUri(serverUri, remoteHostUniqueIdentifier);

                            // the first SS
                            int writtenSize = binaryReader.ReadInt32();
                            senderInputClsseStream = new GenuineChunkedStream(true);
                            GenuineUtility.CopyStreamToStream(responseStream, senderInputClsseStream, writtenSize);

                            writtenSize = binaryReader.ReadInt32();
                            listenerInputClsseStream = new GenuineChunkedStream(true);
                            GenuineUtility.CopyStreamToStream(responseStream, listenerInputClsseStream, writtenSize);
                        }
                    }

                    outputStream.Close();
                }
                catch(Exception ex)
                {
                    if (firstFailure)
                        throw;

                    // LOG:
                    if ( binaryLogWriter != null && binaryLogWriter[LogCategory.Connection] > 0 )
                    {
                        binaryLogWriter.WriteEvent(LogCategory.Connection, "HttpClientConnectionManager.LowLevel_OpenConnection",
                            LogMessageType.ConnectionEstablishing, ex, null, remote, null,
                            GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name, null, null,
                            -1, 0, 0, 0, null, null, null, null,
                            "Exception occurred while establishing the connection to \"{0}\". The connection establishing will be continued.", remote == null ? "?" : remote.Url == null ? "?" : remote.Url);
                    }

                    // try to recover
                    resend = true;
                    continue;
                }
                finally
                {
                    if (requestStream != null)
                        requestStream.Close();
                }

                firstFailure = false;
                resend = false;

                if (httpClientConnection.Sender_ConnectionLevelSecurity != null && ! httpClientConnection.Sender_ConnectionLevelSecurity.IsEstablished)
                    continue;
                if (httpClientConnection.Listener_ConnectionLevelSecurity != null && ! httpClientConnection.Listener_ConnectionLevelSecurity.IsEstablished)
                    continue;
                if (! noClsseToSend)
                    continue;

                break;
            }

            // start listener if it's a persistent connection
            remote.PhysicalAddress = remote.Url;

            // LOG:
            if ( binaryLogWriter != null && binaryLogWriter[LogCategory.HostInformation] > 0 )
            {
                binaryLogWriter.WriteHostInformationEvent("HttpClientConnectionManager.LowLevel_OpenConnection",
                    LogMessageType.HostInformationCreated, null, remote,
                    GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name, httpClientConnection.Sender_ConnectionLevelSecurity,
                    httpClientConnection.Sender_ConnectionLevelSecurity == null ? null : httpClientConnection.Sender_ConnectionLevelSecurity.Name,
                    httpClientConnection.DbgConnectionId,
                    "HostInformation is ready for actions.");
            }

            // LOG:
            if ( binaryLogWriter != null && binaryLogWriter[LogCategory.Connection] > 0 )
            {
                binaryLogWriter.WriteEvent(LogCategory.Connection, "HttpClientConnectionManager.LowLevel_OpenConnection",
                    LogMessageType.ConnectionEstablished, null, null, remote, null,
                    GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name,
                    httpClientConnection.Sender_ConnectionLevelSecurity,
                    httpClientConnection.Sender_ConnectionLevelSecurity == null ? null : httpClientConnection.Sender_ConnectionLevelSecurity.Name,
                    httpClientConnection.DbgConnectionId, (int) genuineConnectionType, 0, 0, this.GetType().Name, remote.Url, remote.Url, null,
                    "The connection to the remote host is established.");
            }

            if (genuineConnectionType == GenuineConnectionType.Persistent)
                this.LowLevel_InitiateListening(httpClientConnection, true);
            return httpClientConnection;
        }
        /// <summary>
        /// Sends the message to the remote host.
        /// </summary>
        /// <param name="message">The message to be sent.</param>
        /// <param name="httpClientConnection">The connection.</param>
        private void InternalSend(Message message, HttpClientConnection httpClientConnection)
        {
            bool sendingLockObtained = false;

            lock (httpClientConnection.SendingLock)
            {
                if (! httpClientConnection.IsSent)
                {
                    httpClientConnection.IsSent = true;
                    sendingLockObtained = true;
                }
                else
                {
                    httpClientConnection.MessageContainer.AddMessage(message, false);
                }
            }

            if (sendingLockObtained)
                this.LowLevel_Sender_Send(message, httpClientConnection, httpClientConnection.OnEndSending, false);
        }
        /// <summary>
        /// Initiates the HTTP request.
        /// </summary>
        /// <param name="httpWebRequest">The instance of the HttpWebRequest class.</param>
        /// <param name="inputStream">The input stream.</param>
        /// <param name="closed">The state event.</param>
        /// <param name="sender">Indicates whether the sender request is being sent.</param>
        /// <param name="asyncCallback">The callback.</param>
        /// <param name="dbgHttpClientConnection">The connection provided for debugging purposes.</param>
        private void LowLevel_InitiateHttpWebRequest(HttpWebRequest httpWebRequest, Stream inputStream, ManualResetEvent closed, bool sender, AsyncCallback asyncCallback, HttpClientConnection dbgHttpClientConnection)
        {
            BinaryLogWriter binaryLogWriter = this.ITransportContext.BinaryLogWriter;

            using(new ReaderAutoLocker(this._disposeLock))
            {
                if (this._disposed)
                    throw OperationException.WrapException(this._disposeReason);
            }

            Stream requestStream = null;

            try
            {
                if (! closed.WaitOne(this._webRequestInitiationTimeout, false))
                    throw GenuineExceptions.Get_Processing_LogicError("[0] Deadlock or a heavy load.");

                closed.Reset();

                requestStream = httpWebRequest.GetRequestStream();

                if (binaryLogWriter != null && binaryLogWriter[LogCategory.LowLevelTransport] > 0 )
                {
                    binaryLogWriter.WriteTransportContentEvent(LogCategory.LowLevelTransport, "HttpClientConnectionManager.LowLevel_InitiateHttpWebRequest",
                        LogMessageType.LowLevelTransport_AsyncSendingInitiating, null, null,
                        dbgHttpClientConnection == null ? null : dbgHttpClientConnection.Remote,
                        binaryLogWriter[LogCategory.LowLevelTransport] > 1 ? inputStream : null,
                        GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name, dbgHttpClientConnection == null ? -1 : dbgHttpClientConnection.DbgConnectionId,
                        (int) inputStream.Length, null, null, null,
                        "HTTP {0} Request is being sent. Size: {1}.", sender ? "SENDER" : "LISTENER", (int) inputStream.Length);
                }

                GenuineUtility.CopyStreamToStream(inputStream, requestStream, (int) inputStream.Length);
                this.IncreaseBytesSent((int) inputStream.Length);

                HttpWebRequestCop webRequestCop = new HttpWebRequestCop(httpWebRequest, asyncCallback, httpWebRequest, this._httpAsynchronousRequestTimeout);
                //httpWebRequest.BeginGetResponse(asyncCallback, httpWebRequest);
            }
            catch(Exception ex)
            {
                if (binaryLogWriter != null && binaryLogWriter[LogCategory.LowLevelTransport] > 0 )
                {
                    binaryLogWriter.WriteEvent(LogCategory.LowLevelTransport, "HttpClientConnectionManager.LowLevel_InitiateHttpWebRequest",
                        LogMessageType.LowLevelTransport_AsyncSendingInitiating, ex, null,
                        dbgHttpClientConnection == null ? null : dbgHttpClientConnection.Remote,
                        null,
                        GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name, null, null,
                        dbgHttpClientConnection == null ? -1 : dbgHttpClientConnection.DbgConnectionId,
                        0, 0, 0, null, null, null, null,
                        "Exception occurred while initiating HTTP request.");
                }

                try
                {
                    httpWebRequest.Abort();
                }
                catch(Exception)
                {
                }

                throw;
            }
            finally
            {
                try
                {
                    if (requestStream != null)
                        requestStream.Close();
                }
                catch(Exception ex)
                {
                    // ignore & warning
                    if (binaryLogWriter != null && binaryLogWriter[LogCategory.LowLevelTransport] > 0 )
                    {
                        binaryLogWriter.WriteEvent(LogCategory.LowLevelTransport, "HttpClientConnectionManager.LowLevel_InitiateHttpWebRequest",
                            LogMessageType.LowLevelTransport_AsyncSendingInitiating, ex, null,
                            dbgHttpClientConnection == null ? null : dbgHttpClientConnection.Remote,
                            null,
                            GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name, null, null,
                            dbgHttpClientConnection == null ? -1 : dbgHttpClientConnection.DbgConnectionId,
                            0, 0, 0, null, null, null, null,
                            "Can't close the stream!");
                    }
                }

                closed.Set();
            }
        }
 /// <summary>
 /// Resets the reestablishing flag.
 /// </summary>
 /// <param name="httpClientConnection">The HTTP client connection.</param>
 /// <param name="sender">A flag indicating the role of the connection.</param>
 public void ReestablishingCompleted(HttpClientConnection httpClientConnection, bool sender)
 {
     HttpClientConnection.ReconnectionContainer reconnectionContainer = sender ? httpClientConnection.SenderReconnectionLock : httpClientConnection.ListenerReconnectionLock;
     reconnectionContainer.IsReconnectionStarted = false;
 }
        /// <summary>
        /// Starts reestablishing if it has not been started.
        /// </summary>
        /// <param name="httpClientConnection">The HTTP client connection.</param>
        /// <param name="exception">The reason of the connection failure.</param>
        /// <param name="sender">A flag indicating the role of the connection.</param>
        public void StartReestablishingIfNecessary(HttpClientConnection httpClientConnection, Exception exception, bool sender)
        {
            BinaryLogWriter binaryLogWriter = this.ITransportContext.BinaryLogWriter;

            HttpClientConnection.ReconnectionContainer reconnectionContainer = sender ? httpClientConnection.SenderReconnectionLock : httpClientConnection.ListenerReconnectionLock;
            lock (reconnectionContainer.SyncLock)
            {
                if (! reconnectionContainer.IsReconnectionStarted)
                {
                    // LOG:
                    if ( binaryLogWriter != null )
                    {
                        binaryLogWriter.WriteEvent(LogCategory.Debugging, "HttpClientConnectionManager.StartReestablishingIfNecessary",
                            LogMessageType.ConnectionReestablishing, exception, null, null, null,
                            GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name,
                            null, null, -1, 0, 0, 0, null, null, null, null,
                            "Reconnection is being started.");
                    }

                    reconnectionContainer.IsReconnectionStarted = true;
                    reconnectionContainer.ReconnectionStartedAt = GenuineUtility.TickCount;

                    FailedHttpRequest failedHttpRequest = new FailedHttpRequest();
                    failedHttpRequest.HttpClientConnection = httpClientConnection;
                    failedHttpRequest.Exception = exception;
                    failedHttpRequest.Sender = sender;
                    GenuineThreadPool.QueueUserWorkItem(new WaitCallback(this.ReestablishFailedConnection), failedHttpRequest, true);
                }
                else
                {
                    // LOG:
                    if ( binaryLogWriter != null )
                    {
                        binaryLogWriter.WriteEvent(LogCategory.Debugging, "HttpClientConnectionManager.StartReestablishingIfNecessary",
                            LogMessageType.ConnectionReestablishing, exception, null, null, null,
                            GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name,
                            null, null, -1, 0, 0, 0, null, null, null, null,
                            "Reconnection is already in progress.");
                    }

                    reconnectionContainer.RequestFailed = true;
                }
            }
        }
        /// <summary>
        /// Finishes sending a message through the connection.
        /// </summary>
        /// <param name="httpClientConnection">The connection.</param>
        /// <param name="httpWebResponse">The received response.</param>
        public void Pool_Sender_OnEndSending(HttpClientConnection httpClientConnection, HttpWebResponse httpWebResponse)
        {
            BinaryLogWriter binaryLogWriter = this.ITransportContext.BinaryLogWriter;
            Stream inputStream = null;

            try
            {
                httpClientConnection.Remote.Renew(this._hostRenewingSpan, false);
                httpClientConnection.LastMessageWasReceviedAt = GenuineUtility.TickCount;
                httpClientConnection.SignalState(GenuineEventType.GeneralConnectionEstablished, null, null);

                httpClientConnection.SentContent.Close();
                httpClientConnection.SentContent = null;
                httpClientConnection.MessagesBeingSent.Clear();

                // process the content
                inputStream = httpWebResponse.GetResponseStream();

                // LOG:
                if ( binaryLogWriter != null && binaryLogWriter[LogCategory.LowLevelTransport] > 0 )
                {
                    GenuineChunkedStream content = null;
                    if (binaryLogWriter[LogCategory.Transport] > 1)
                    {
                        content = new GenuineChunkedStream(false);
                        GenuineUtility.CopyStreamToStream(inputStream, content, (int) httpWebResponse.ContentLength);
                    }

                    binaryLogWriter.WriteTransportContentEvent(LogCategory.LowLevelTransport, "HttpClientConnectionManager.Pool_Sender_OnEndSending",
                        LogMessageType.AsynchronousSendingFinished, null, null, httpClientConnection.Remote,
                        binaryLogWriter[LogCategory.LowLevelTransport] > 1 ? content : null,
                        GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name, httpClientConnection.DbgConnectionId,
                        (int) httpWebResponse.ContentLength, null, null, null,
                        "The content of the response received by the sender connection.");

                    if (binaryLogWriter[LogCategory.Transport] > 1)
                        inputStream = content;
                }

                BinaryReader binaryReader = new BinaryReader(inputStream);
                string serverUri;
                int sequenceNo;
                HttpPacketType httpPacketType;
                int remoteHostUniqueIdentifier;
                HttpMessageCoder.ReadResponseHeader(binaryReader, out serverUri, out sequenceNo, out httpPacketType, out remoteHostUniqueIdentifier);

                if (sequenceNo != httpClientConnection.SendSequenceNo)
                    throw GenuineExceptions.Get_Receive_IncorrectData();
                if (httpClientConnection.GenuineConnectionType == GenuineConnectionType.Persistent)
                    httpClientConnection.Remote.UpdateUri(serverUri, remoteHostUniqueIdentifier);

                if ( binaryLogWriter != null && binaryLogWriter[LogCategory.LowLevelTransport] > 0 )
                {
                    binaryLogWriter.WriteEvent(LogCategory.LowLevelTransport, "HttpClientConnectionManager.Pool_Sender_OnEndSending",
                        LogMessageType.LowLevelTransport_AsyncSendingCompleted, null, null, httpClientConnection.Remote, null,
                        GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name, httpClientConnection.Sender_ConnectionLevelSecurity,
                        httpClientConnection.Sender_ConnectionLevelSecurity == null ? null : httpClientConnection.Sender_ConnectionLevelSecurity.Name,
                        httpClientConnection.DbgConnectionId, (int) httpPacketType, sequenceNo, 0, null, null, null, null,
                        "SENDER invocation completed. Type of the packet: {0}. Server Uri: {1}. Seq No: {2}",
                        Enum.Format(typeof(HttpPacketType), httpPacketType, "g"), serverUri, sequenceNo);
                }

                if (httpPacketType == HttpPacketType.Desynchronization)
                {
                    this.ConnectionFailed(httpClientConnection, true, GenuineExceptions.Get_Channel_Desynchronization(), false);
                    return ;
                }

                if (httpPacketType == HttpPacketType.SenderError)
                {
                    Exception deserializedException = null;

                    try
                    {
                        BinaryFormatter binaryFormatter = new BinaryFormatter(new RemotingSurrogateSelector(), new StreamingContext(StreamingContextStates.Other));
                        deserializedException = binaryFormatter.Deserialize(inputStream) as Exception;
                    }
                    catch
                    {
                    }

                    if (deserializedException != null)
                        this.ConnectionFailed(httpClientConnection, true, GenuineExceptions.Get_Receive_ConnectionClosed(deserializedException.Message), false);
                    else
                        this.ConnectionFailed(httpClientConnection, true, GenuineExceptions.Get_Receive_ConnectionClosed("Remote host was not able to parse the request. Probably due to the security reasons."), false);
                    return ;
                }

                // fetch and process messages
                this.LowLevel_ParseLabelledStream(inputStream, httpClientConnection.Sender_ReceiveBuffer, httpClientConnection, httpClientConnection.Sender_ConnectionLevelSecurity);
            }
            finally
            {
                if (inputStream != null)
                    inputStream.Close();
                httpWebResponse.Close();

                // TODO: remove this
                if ( binaryLogWriter != null && binaryLogWriter[LogCategory.Debugging] > 0 )
                {
                    binaryLogWriter.WriteEvent(LogCategory.Debugging, "HttpClientConnectionManager.Pool_Sender_OnEndSending",
                        LogMessageType.DebuggingSuccess, null, null, httpClientConnection.Remote, null,
                        GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name, httpClientConnection.Sender_ConnectionLevelSecurity,
                        null,
                        httpClientConnection.DbgConnectionId, -1, -1, -1, null, null, null, null,
                        "HttpClientConnectionManager.Pool_Sender_OnEndSending is completed.");
                }

            }

            GenuineThreadPool.QueueUserWorkItem(this._pool_Sender_OnEndSending_ContinueExchange, httpClientConnection, false);
        }
        /// <summary>
        /// Reads messages from the stream and processes them.
        /// </summary>
        /// <param name="stream">The source stream.</param>
        /// <param name="intermediateBuffer">The intermediate buffer.</param>
        /// <param name="httpClientConnection">The connection.</param>
        /// <param name="connectionLevelSecuritySession">The Connection Level Security Session that decrypted this message.</param>
        public void LowLevel_ParseLabelledStream(Stream stream, byte[] intermediateBuffer, HttpClientConnection httpClientConnection, SecuritySession connectionLevelSecuritySession)
        {
            bool directExecution = httpClientConnection.GenuineConnectionType == GenuineConnectionType.Invocation;

            BinaryReader binaryReader = new BinaryReader(stream);

            while ( binaryReader.ReadByte() == 0 )
            {
                using (LabelledStream labelledStream = new LabelledStream(this.ITransportContext, stream, intermediateBuffer))
                {
                    if (directExecution)
                        this.ITransportContext.IIncomingStreamHandler.HandleMessage(labelledStream, httpClientConnection.Remote, httpClientConnection.GenuineConnectionType, httpClientConnection.ConnectionName, httpClientConnection.DbgConnectionId, true, null, connectionLevelSecuritySession, null);
                    else
                    {
                        GenuineChunkedStream receivedContent = new GenuineChunkedStream(true);
                        GenuineUtility.CopyStreamToStream(labelledStream, receivedContent);
                        this.ITransportContext.IIncomingStreamHandler.HandleMessage(receivedContent, httpClientConnection.Remote, httpClientConnection.GenuineConnectionType, httpClientConnection.ConnectionName, httpClientConnection.DbgConnectionId, false, null, connectionLevelSecuritySession, null);
                    }
                }
            }
        }
        /// <summary>
        /// Finishes sending a message through the connection.
        /// </summary>
        /// <param name="httpClientConnection">The connection.</param>
        /// <param name="httpWebResponse">The received response.</param>
        public void Listener_OnEndReceiving(HttpClientConnection httpClientConnection, HttpWebResponse httpWebResponse)
        {
            BinaryLogWriter binaryLogWriter = this.ITransportContext.BinaryLogWriter;
            Stream inputStream = null;

            try
            {
            #if DEBUG
                Debug.Assert(httpClientConnection.GenuineConnectionType == GenuineConnectionType.Persistent);
            #endif

                httpClientConnection.Remote.Renew(this._hostRenewingSpan, false);
                httpClientConnection.LastMessageWasReceviedAt = GenuineUtility.TickCount;
                httpClientConnection.SignalState(GenuineEventType.GeneralConnectionEstablished, null, null);

                // process the content
                inputStream = httpWebResponse.GetResponseStream();

                // LOG:
                if ( binaryLogWriter != null && binaryLogWriter[LogCategory.LowLevelTransport] > 0 )
                {
                    bool writeContent = binaryLogWriter[LogCategory.LowLevelTransport] > 1;
                    GenuineChunkedStream content = null;
                    if (writeContent)
                    {
                        content = new GenuineChunkedStream(false);
                        GenuineUtility.CopyStreamToStream(inputStream, content, (int) httpWebResponse.ContentLength);
                    }

                    binaryLogWriter.WriteTransportContentEvent(LogCategory.LowLevelTransport, "HttpClientConnectionManager.Listener_OnEndReceiving",
                        LogMessageType.LowLevelTransport_AsyncReceivingCompleted, null, null, httpClientConnection.Remote,
                        writeContent ? content : null,
                        GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name,
                        httpClientConnection.DbgConnectionId, (int) httpWebResponse.ContentLength,
                        null, null, null,
                        "The content has been received.");

                    if (writeContent)
                        inputStream = content;
                }

                if (httpClientConnection.Listener_ConnectionLevelSecurity != null)
                    inputStream = httpClientConnection.Listener_ConnectionLevelSecurity.Decrypt(inputStream);

                BinaryReader binaryReader = new BinaryReader(inputStream);
                string serverUri;
                int sequenceNo;
                HttpPacketType httpPacketType;
                int remoteHostUniqueIdentifier;
                HttpMessageCoder.ReadResponseHeader(binaryReader, out serverUri, out sequenceNo, out httpPacketType, out remoteHostUniqueIdentifier);

                // LOG:
                if ( binaryLogWriter != null && binaryLogWriter[LogCategory.Connection] > 0 )
                {
                    binaryLogWriter.WriteEvent(LogCategory.Connection, "HttpClientConnectionManager.Listener_OnEndReceiving",
                        LogMessageType.ReceivingFinished, null, null, httpClientConnection.Remote, null,
                        GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name, httpClientConnection.Listener_ConnectionLevelSecurity, null,
                        httpClientConnection.DbgConnectionId, 0, 0, 0, null, null, null, null,
                        "A response to the listener request has been received. Server uri: {0}. Sequence no: {1}. Packet type: {2}. Content-encoding: {3}. Content-length: {4}. Protocol version: {5}. Response uri: \"{6}\". Server: \"{7}\". Status code: {8}. Status description: \"{9}\".",
                        serverUri, sequenceNo, Enum.Format(typeof(HttpPacketType), httpPacketType, "g"),
                        httpWebResponse.ContentEncoding, httpWebResponse.ContentLength,
                        httpWebResponse.ProtocolVersion, httpWebResponse.ResponseUri,
                        httpWebResponse.Server, httpWebResponse.StatusCode, httpWebResponse.StatusDescription);
                }

                if (httpPacketType == HttpPacketType.Desynchronization)
                    throw GenuineExceptions.Get_Channel_Desynchronization();

                if (sequenceNo != httpClientConnection.ListenerSequenceNo)
                    throw GenuineExceptions.Get_Processing_LogicError(
                        string.Format("Impossible situation. The request stream number: {0}. The received stream number: {1}.", httpClientConnection.ListenerSequenceNo, sequenceNo)
                        );

                if (httpClientConnection.GenuineConnectionType == GenuineConnectionType.Persistent)
                    httpClientConnection.Remote.UpdateUri(serverUri, remoteHostUniqueIdentifier);

                // if the remote host has asked to terminate a connection
                if (httpPacketType == HttpPacketType.ClosedManually || httpPacketType == HttpPacketType.Desynchronization)
                    throw GenuineExceptions.Get_Receive_ConnectionClosed();

                // fetch and process messages
                if (httpPacketType != HttpPacketType.ListenerTimedOut)
                    this.LowLevel_ParseLabelledStream(inputStream, httpClientConnection.Listener_ReceiveBuffer, httpClientConnection, httpClientConnection.Listener_ConnectionLevelSecurity);

                GenuineUtility.CopyStreamToStream(inputStream, Stream.Null);
            }
            catch(Exception ex)
            {
                this.ConnectionFailed(httpClientConnection, false, ex, true);
                return ;
            }
            finally
            {
                if (inputStream != null)
                    inputStream.Close();
                httpWebResponse.Close();
            }

            GenuineThreadPool.QueueUserWorkItem(new WaitCallback(this.Listener_OnEndReceiving_ContinueExchange), httpClientConnection, false);
        }
        /// <summary>
        /// Sends the message to the remote host through the sender connection.
        /// </summary>
        /// <param name="message">Message to be sent.</param>
        /// <param name="httpClientConnection">The connection.</param>
        /// <param name="asyncCallback">The callback to be called after the operation will be completed.</param>
        /// <param name="repeatSending">Whether to send the previous content again.</param>
        private void LowLevel_Sender_Send(Message message, HttpClientConnection httpClientConnection, AsyncCallback asyncCallback, bool repeatSending)
        {
            BinaryLogWriter binaryLogWriter = this.ITransportContext.BinaryLogWriter;

            // connection lock obtained, assemble the packet and send it
            try
            {
                if (! repeatSending)
                {
                    httpClientConnection.SendSequenceNo ++;
                    httpClientConnection.LastMessageWasSentAt = GenuineUtility.TickCount;

                    httpClientConnection.SentContent = new GenuineChunkedStream(false);
                    MessageCoder.FillInLabelledStream(message, httpClientConnection.MessageContainer,
                        httpClientConnection.MessagesBeingSent, httpClientConnection.SentContent,
                        httpClientConnection.Sender_SendBuffer,
                        (int) this.ITransportContext.IParameterProvider[GenuineParameter.HttpRecommendedPacketSize]);

                    // LOG:
                    if ( binaryLogWriter != null && binaryLogWriter[LogCategory.Transport] > 0 )
                    {
                        for ( int i = 0; i < httpClientConnection.MessagesBeingSent.Count; i++)
                        {
                            Message nextMessage = (Message) httpClientConnection.MessagesBeingSent[i];

                            binaryLogWriter.WriteEvent(LogCategory.Transport, "HttpClientConnectionManager.LowLevel_Sender_Send",
                                LogMessageType.MessageIsSentAsynchronously, null, nextMessage, httpClientConnection.Remote, null,
                                GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name, httpClientConnection.Sender_ConnectionLevelSecurity,
                                null,
                                httpClientConnection.DbgConnectionId, httpClientConnection.SendSequenceNo, 0, 0, null, null, null, null,
                                "The message will be sent in the SENDER stream N: {0}.", httpClientConnection.SendSequenceNo);
                        }
                    }

                    // apply CLSSE
                    if (httpClientConnection.Sender_ConnectionLevelSecurity != null)
                    {
                        GenuineChunkedStream encryptedContent = new GenuineChunkedStream(false);
                        httpClientConnection.Sender_ConnectionLevelSecurity.Encrypt(httpClientConnection.SentContent, encryptedContent);
                        httpClientConnection.SentContent = encryptedContent;
                    }

                    // prepare the final version of the content
                    GenuineChunkedStream resultStream = new GenuineChunkedStream(false);
                    BinaryWriter binaryWriter = new BinaryWriter(resultStream);
                    HttpMessageCoder.WriteRequestHeader(binaryWriter, MessageCoder.PROTOCOL_VERSION, httpClientConnection.GenuineConnectionType, httpClientConnection.HostId, HttpPacketType.Usual, httpClientConnection.SendSequenceNo, httpClientConnection.ConnectionName, httpClientConnection.Remote.LocalHostUniqueIdentifier);
                    if (httpClientConnection.SentContent.CanSeek)
                        resultStream.WriteStream(httpClientConnection.SentContent);
                    else
                        GenuineUtility.CopyStreamToStream(httpClientConnection.SentContent, resultStream);

                    httpClientConnection.SentContent = resultStream;
                }
                else
                {
                    httpClientConnection.SentContent.Position = 0;
                }

                // try to send it
                httpClientConnection.Sender = httpClientConnection.InitializeRequest(true, httpClientConnection._keepalive);
                httpClientConnection.Sender.ContentLength = httpClientConnection.SentContent.Length;

                this.LowLevel_InitiateHttpWebRequest(httpClientConnection.Sender, httpClientConnection.SentContent, httpClientConnection.SenderClosed, true, asyncCallback, httpClientConnection);
            }
            catch(Exception ex)
            {
                // sending failed, rollback the entire operation

                // LOG:
                if ( binaryLogWriter != null && binaryLogWriter[LogCategory.Connection] > 0 )
                {
                    binaryLogWriter.WriteEvent(LogCategory.Connection, "HttpClientConnectionManager.LowLevel_Sender_Send",
                        LogMessageType.AsynchronousSendingFinished, ex, null, httpClientConnection.Remote, null,
                        GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name, null, null,
                        httpClientConnection.DbgConnectionId, 0, 0, 0, null, null, null, null,
                        "Error occurred while sending a message to the remote host.");
                }

                this.StartReestablishingIfNecessary(httpClientConnection, ex, true);
            }
        }
        /// <summary>
        /// Processes failed or closed connections.
        /// </summary>
        /// <param name="httpClientConnection">The connection.</param>
        /// <param name="sender">The type of the failed connection (P/Async).</param>
        /// <param name="exception">The exception.</param>
        /// <param name="tryToReestablish">True if it's a good idea to try to reestablish the connection.</param>
        public void ConnectionFailed(HttpClientConnection httpClientConnection, bool sender, Exception exception, bool tryToReestablish)
        {
            BinaryLogWriter binaryLogWriter = this.ITransportContext.BinaryLogWriter;

            try
            {
                if (tryToReestablish)
                    tryToReestablish = ! ConnectionManager.IsExceptionCritical(exception as OperationException);

                // LOG:
                if ( binaryLogWriter != null && binaryLogWriter[LogCategory.Connection] > 0 )
                {
                    binaryLogWriter.WriteEvent(LogCategory.Connection, "HttpClientConnectionManager.ConnectionFailed",
                        LogMessageType.ConnectionFailed, exception, null, httpClientConnection.Remote, null,
                        GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name, null, null,
                        httpClientConnection.DbgConnectionId,
                        0, 0, 0, null, null, null, null,
                        "Connection failure. Sender: {0}. Connection type: {1}. Try to reestablish: {2}.",
                        sender.ToString(), Enum.GetName(typeof(GenuineConnectionType), httpClientConnection.GenuineConnectionType),
                        tryToReestablish.ToString());
                }

                using (new ReaderAutoLocker(this._disposeLock))
                {
                    if (this._disposed)
                        tryToReestablish = false;
                }

                lock (httpClientConnection.Remote.PersistentConnectionEstablishingLock)
                {
                    if (! tryToReestablish || httpClientConnection._disposed)
                    {
                        using (new ReaderAutoLocker(this._disposeLock))
                        {
                            this._persistent.Remove(httpClientConnection.Remote.Url);
                        }

                        // close the content
                        if (httpClientConnection.SentContent != null)
                        {
                            httpClientConnection.SentContent.Close();
                            httpClientConnection.SentContent = null;
                        }

                        // release all resources
                        this.ITransportContext.KnownHosts.ReleaseHostResources(httpClientConnection.Remote, exception);
                        foreach (Message message in httpClientConnection.MessagesBeingSent)
                            this.ITransportContext.IIncomingStreamHandler.DispatchException(message, exception);
                        httpClientConnection.MessagesBeingSent.Clear();
                        httpClientConnection.Dispose(exception);

                        httpClientConnection.SignalState(GenuineEventType.GeneralConnectionClosed, exception, null);
                        if (exception is OperationException && ((OperationException) exception).OperationErrorMessage.ErrorIdentifier == "GenuineChannels.Exception.Receive.ServerHasBeenRestarted")
                            httpClientConnection.SignalState(GenuineEventType.GeneralServerRestartDetected, exception, null);

                        // LOG:
                        if ( binaryLogWriter != null && binaryLogWriter[LogCategory.Connection] > 0 )
                        {
                            binaryLogWriter.WriteEvent(LogCategory.Connection, "HttpClientConnectionManager.ConnectionFailed",
                                LogMessageType.ConnectionFailed, exception, null, httpClientConnection.Remote, null,
                                GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name, null, null,
                                httpClientConnection.DbgConnectionId,
                                0, 0, 0, null, null, null, null,
                                "The connection has been completely terminated and removed from all collection. Sender: {0}. Connection type: {1}. Try to reestablish: {2}.",
                                sender.ToString(), Enum.GetName(typeof(GenuineConnectionType), httpClientConnection.GenuineConnectionType),
                                tryToReestablish.ToString());
                        }

                        return ;
                    }

                    httpClientConnection.SignalState(GenuineEventType.GeneralConnectionReestablishing, exception, null);

                    HttpClientConnection.ReconnectionContainer reconnectionContainer = sender ? httpClientConnection.SenderReconnectionLock : httpClientConnection.ListenerReconnectionLock;
                    lock (reconnectionContainer.SyncLock)
                    {
                        if (GenuineUtility.IsTimeoutExpired(reconnectionContainer.ReconnectionStartedAt + GenuineUtility.ConvertToMilliseconds(this.ITransportContext.IParameterProvider[GenuineParameter.MaxTimeSpanToReconnect])))
                        {
                            // LOG:
                            if ( binaryLogWriter != null && binaryLogWriter[LogCategory.Connection] > 0 )
                            {
                                binaryLogWriter.WriteEvent(LogCategory.Connection, "HttpClientConnectionManager.ConnectionFailed",
                                    LogMessageType.ConnectionReestablishing, GenuineExceptions.Get_Debugging_GeneralWarning("Connection was not reestablished within the specified time boundaries."),
                                    null, httpClientConnection.Remote, null,
                                    GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name, null, null,
                                    httpClientConnection.DbgConnectionId,
                                    0, 0, 0, null, null, null, null,
                                    "The connection has not been reestablished within the specified time boundaries.");
                            }

                            // just close the connection
                            using (new ReaderAutoLocker(this._disposeLock))
                            {
                                this._persistent.Remove(httpClientConnection.Remote.Url);
                            }

                            this.ITransportContext.KnownHosts.ReleaseHostResources(httpClientConnection.Remote, exception);
                            httpClientConnection.Dispose(exception);
                            httpClientConnection.MessageContainer.Dispose(exception);

                            // and fire a warning
                            httpClientConnection.SignalState(GenuineEventType.GeneralConnectionClosed, exception, null);
                            return ;
                        }

                        // resend the content or rerequest the previous content
                        if (sender)
                        {
                            if (httpClientConnection.SentContent != null)
                                this.LowLevel_Sender_Send(null, httpClientConnection, httpClientConnection.OnEndSending, true);
                        }
                        else
                            this.LowLevel_InitiateListening(httpClientConnection, false);
                    }
                }
            }
            catch(Exception ex)
            {
                if ( binaryLogWriter != null )
                    binaryLogWriter.WriteImplementationWarningEvent("HttpClientConnectionManager.ConnectionFailed",
                        LogMessageType.Error, ex, GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name,
                        "Unexpected exception occurred in the HttpClientConnectionManager.ConnectionFailed method. Most likely, something must be fixed.");
            }
        }