private void HandleDeserializationError(ClientResponseContext context, int?messageId, RpcErrorMessage rpcError, string message, Func <byte[]> invalidRequestHeaderProvider)
        {
            MsgPackRpcClientProtocolsTrace.TraceRpcError(
                rpcError.Error,
                "Deserialization error. {0} {{ \"Message ID\" : {1}, \"Error\" : {2} }}",
                message,
                messageId == null ? "(null)" : messageId.ToString(),
                rpcError
                );

            if (invalidRequestHeaderProvider != null && MsgPackRpcClientProtocolsTrace.ShouldTrace(MsgPackRpcClientProtocolsTrace.DumpInvalidResponseHeader))
            {
                var array = invalidRequestHeaderProvider();
                MsgPackRpcClientProtocolsTrace.TraceData(MsgPackRpcClientProtocolsTrace.DumpInvalidResponseHeader, BitConverter.ToString(array), array);
            }

            this.RaiseError(messageId, context.SessionId, GetRemoteEndPoint(this.BoundSocket, context), rpcError, context.CompletedSynchronously);

            context.NextProcess = this.DumpCorrupttedData;
        }
        /// <summary>
        ///		Called when asynchronous 'Receive' operation is completed.
        /// </summary>
        /// <param name="context">Context information.</param>
        ///	<exception cref="InvalidOperationException">
        ///		This instance is not in 'Idle' nor 'Receiving' state.
        ///	</exception>
        ///	<exception cref="ObjectDisposedException">
        ///		This instance is disposed.
        ///	</exception>
        protected virtual void OnReceived(ClientResponseContext context)
        {
            if (context == null)
            {
                throw new ArgumentNullException("context");
            }

            Contract.EndContractBlock();

            if (MsgPackRpcClientProtocolsTrace.ShouldTrace(MsgPackRpcClientProtocolsTrace.ReceiveInboundData))
            {
                var socket = this.BoundSocket;
                MsgPackRpcClientProtocolsTrace.TraceEvent(
                    MsgPackRpcClientProtocolsTrace.ReceiveInboundData,
                    "Receive response. {{ \"SessionID\" : {0}, \"Socket\" : 0x{1:X}, \"RemoteEndPoint\" : \"{2}\", \"LocalEndPoint\" : \"{3}\", \"BytesTransfered\" : {4} }}",
                    context.SessionId,
                    GetHandle(socket),
                    GetRemoteEndPoint(socket, context),
                    GetLocalEndPoint(socket),
                    context.BytesTransferred
                    );
            }

            if (context.BytesTransferred == 0)
            {
                if (Interlocked.CompareExchange(ref this._shutdownSource, ( int )ShutdownSource.Server, 0) == 0)
                {
                    // Server sent shutdown response.
                    this.ShutdownReceiving();

                    // recv() returns 0 when the server socket shutdown gracefully.
                    var socket = this.BoundSocket;
                    MsgPackRpcClientProtocolsTrace.TraceEvent(
                        MsgPackRpcClientProtocolsTrace.DetectServerShutdown,
                        "Server shutdown current socket. {{ \"Socket\" : 0x{0:X}, \"RemoteEndPoint\" : \"{1}\", \"LocalEndPoint\" : \"{2}\" }}",
                        GetHandle(socket),
                        GetRemoteEndPoint(socket, context),
                        GetLocalEndPoint(socket)
                        );
                }
                else if (this.IsClientShutdown)
                {
                    // Client was started shutdown.
                    this.ShutdownReceiving();
                }

                if (!context.ReceivedData.Any(segment => 0 < segment.Count))
                {
                    // There are no data to handle.
                    this.FinishReceiving(context);
                    return;
                }
            }
            else
            {
                context.ShiftCurrentReceivingBuffer();
            }

            if (MsgPackRpcClientProtocolsTrace.ShouldTrace(MsgPackRpcClientProtocolsTrace.DeserializeResponse))
            {
                MsgPackRpcClientProtocolsTrace.TraceEvent(
                    MsgPackRpcClientProtocolsTrace.DeserializeResponse,
                    "Deserialize response. {{ \"SessionID\" : {0}, \"Length\" : {1} }}",
                    context.SessionId,
                    context.ReceivedData.Sum(item => ( long )item.Count)
                    );
            }

            // Go deserialization pipeline.

            // Exceptions here means message error.
            try
            {
                ApplyFilters(this._beforeDeserializationFilters, context);
            }
            catch (RpcException ex)
            {
                this.HandleDeserializationError(context, TryDetectMessageId(context), new RpcErrorMessage(ex.RpcError, ex.Message, ex.DebugInformation), "Filter rejects message.", () => context.ReceivedData.SelectMany(s => s.AsEnumerable()).ToArray());
                this.FinishReceiving(context);
                return;
            }

            if (!context.NextProcess(context))
            {
                if (this.IsServerShutdown)
                {
                    this.ShutdownReceiving();
                }
                else if (this.CanResumeReceiving)
                {
                    // Wait to arrive more data from server.
                    this.ReceiveCore(context);
                    return;
                }

                this.FinishReceiving(context);
                return;
            }
        }
        /// <summary>
        ///		Called when asynchronous 'Send' operation is completed.
        /// </summary>
        /// <param name="context">Context information.</param>
        /// <returns>
        ///		<c>true</c>, if the subsequent request is already received;
        ///		<c>false</c>, otherwise.
        /// </returns>
        ///	<exception cref="InvalidOperationException">
        ///		This instance is not in 'Sending' state.
        ///	</exception>
        ///	<exception cref="ObjectDisposedException">
        ///		This instance is disposed.
        ///	</exception>
        protected virtual void OnSent(ClientRequestContext context)
        {
            if (MsgPackRpcClientProtocolsTrace.ShouldTrace(MsgPackRpcClientProtocolsTrace.SentOutboundData))
            {
                var socket = this.BoundSocket;
                MsgPackRpcClientProtocolsTrace.TraceEvent(
                    MsgPackRpcClientProtocolsTrace.SentOutboundData,
                    "Sent request/notification. {{ \"SessionID\" : {0}, \"Socket\" : 0x{1:X}, \"RemoteEndPoint\" : \"{2}\", \"LocalEndPoint\" : \"{3}\", \"Type\" : \"{4}\", \"MessageID\" : {5}, \"Method\" : \"{6}\", \"BytesTransferred\" : {7} }}",
                    context.SessionId,
                    GetHandle(socket),
                    GetRemoteEndPoint(socket, context),
                    GetLocalEndPoint(socket),
                    context.MessageType,
                    context.MessageId,
                    context.MethodName,
                    context.BytesTransferred
                    );
            }

            context.StopWatchTimeout();
            context.Timeout -= this.OnSendTimeout;

            context.ClearBuffers();

            if (context.MessageType == MessageType.Notification)
            {
                try
                {
                    Action <Exception, bool> handler = null;
                    try
                    {
                        this._pendingNotificationTable.TryRemove(context.SessionId, out handler);
                    }
                    finally
                    {
                        var rpcError = context.SocketError.ToClientRpcError();
                        if (handler != null)
                        {
                            handler(rpcError.IsSuccess ? null : rpcError.ToException(), context.CompletedSynchronously);
                        }
                    }
                }
                finally
                {
                    this.Manager.ReturnRequestContext(context);
                    this.OnProcessFinished();
                    this.Manager.ReturnTransport(this);
                }
            }
            else
            {
                if (this.Manager.Configuration.WaitTimeout != null &&
                    (this.Manager.Configuration.WaitTimeout.Value - context.ElapsedTime).TotalMilliseconds < 1.0)
                {
                    this.OnWaitTimeout(context);
                    this.Manager.ReturnRequestContext(context);
                    this.Manager.ReturnTransport(this);
                    return;
                }

                var responseContext = this.Manager.GetResponseContext(this, context.RemoteEndPoint);

                if (this.Manager.Configuration.WaitTimeout != null)
                {
                    responseContext.Timeout += this.OnReceiveTimeout;
                    responseContext.StartWatchTimeout(this.Manager.Configuration.WaitTimeout.Value - context.ElapsedTime);
                }

                this.Manager.ReturnRequestContext(context);
                this.Receive(responseContext);
            }
        }
        /// <summary>
        ///		Sends a request or notification message with the specified context.
        /// </summary>
        /// <param name="context">The context information.</param>
        /// <exception cref="ArgumentNullException">
        ///		<paramref name="context"/> is <c>null</c>.
        /// </exception>
        /// <exception cref="ArgumentException">
        ///		<paramref name="context"/> is not bound to this transport.
        /// </exception>
        /// <exception cref="ObjectDisposedException">
        ///		This instance has been disposed.
        /// </exception>
        /// <exception cref="InvalidOperationException">
        ///		This instance is in shutdown.
        ///		Or the message ID or session ID is duplicated.
        /// </exception>
        /// <exception cref="RpcException">
        ///		Failed to send request or notification to the server.
        /// </exception>
        public void Send(ClientRequestContext context)
        {
            if (context == null)
            {
                throw new ArgumentNullException("context");
            }

            if (!Object.ReferenceEquals(context.BoundTransport, this))
            {
                throw new ArgumentException("Context is not bound to this object.", "context");
            }

            this.VerifyIsNotDisposed();

            if (this.IsClientShutdown)
            {
                throw new InvalidOperationException("This transport is in shutdown.");
            }

            Contract.EndContractBlock();

            if (this.IsServerShutdown)
            {
                throw new RpcErrorMessage(RpcError.TransportError, "Server did shutdown socket.", null).ToException();
            }

            context.Prepare(this.CanUseChunkedBuffer);

            if (context.MessageType == MessageType.Request)
            {
                if (!this._pendingRequestTable.TryAdd(context.MessageId.Value, context.RequestCompletionCallback))
                {
                    throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture, "Message ID '{0}' is already used.", context.MessageId));
                }
            }
            else
            {
                if (!this._pendingNotificationTable.TryAdd(context.SessionId, context.NotificationCompletionCallback))
                {
                    throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture, "Session ID '{0}' is already used.", context.MessageId));
                }
            }

            if (MsgPackRpcClientProtocolsTrace.ShouldTrace(MsgPackRpcClientProtocolsTrace.SendOutboundData))
            {
                var socket = this.BoundSocket;
                MsgPackRpcClientProtocolsTrace.TraceEvent(
                    MsgPackRpcClientProtocolsTrace.SendOutboundData,
                    "Send request/notification. {{ \"SessionID\" : {0}, \"Socket\" : 0x{1:X}, \"RemoteEndPoint\" : \"{2}\", \"LocalEndPoint\" : \"{3}\", \"Type\" : \"{4}\", \"MessageID\" : {5}, \"Method\" : \"{6}\", \"BytesTransferring\" : {7} }}",
                    context.SessionId,
                    GetHandle(socket),
                    GetRemoteEndPoint(socket, context),
                    GetLocalEndPoint(socket),
                    context.MessageType,
                    context.MessageId,
                    context.MethodName,
                    context.SendingBuffer.Sum(segment => ( long )segment.Count)
                    );
            }

            // Because exceptions here means client error, it should be handled like other client error.
            // Therefore, no catch clauses here.
            ApplyFilters(this._afterSerializationFilters, context);

            if (this.Manager.Configuration.WaitTimeout != null)
            {
                context.Timeout += this.OnSendTimeout;
                context.StartWatchTimeout(this.Manager.Configuration.WaitTimeout.Value);
            }

            this.SendCore(context);
        }