/// <summary>
        ///		Receives byte stream from remote end point.
        /// </summary>
        /// <param name="context">Context information.</param>
        ///	<exception cref="InvalidOperationException">
        ///		This instance is not in 'Idle' state.
        ///	</exception>
        ///	<exception cref="ObjectDisposedException">
        ///		This instance is disposed.
        ///	</exception>
        private void Receive(ClientResponseContext context)
        {
            Contract.Assert(context != null);
            Contract.Assert(context.BoundTransport == this, "Context is not bound to this object.");

            // First, drain last received request.
            if (context.ReceivedData.Any(segment => 0 < segment.Count))
            {
                this.DrainRemainingReceivedData(context);
            }
            else
            {
                // There might be dirty data due to client shutdown.
                context.ReceivedData.Clear();
                Array.Clear(context.CurrentReceivingBuffer, 0, context.CurrentReceivingBuffer.Length);

                context.PrepareReceivingBuffer();

                var socket = this.BoundSocket;
                MsgPackRpcClientProtocolsTrace.TraceEvent(
                    MsgPackRpcClientProtocolsTrace.BeginReceive,
                    "Receive inbound data. {{  \"Socket\" : 0x{0:X}, \"RemoteEndPoint\" : \"{1}\", \"LocalEndPoint\" : \"{2}\" }}",
                    GetHandle(socket),
                    GetRemoteEndPoint(socket, context),
                    GetLocalEndPoint(socket)
                    );
                this.ReceiveCore(context);
            }
        }
Пример #2
0
        /// <summary>
        ///		Unpack Message ID part on response message.
        /// </summary>
        /// <param name="context">Context information.</param>
        /// <returns>
        ///		<c>true</c>, if the pipeline is finished;
        ///		<c>false</c>, the pipeline is interruppted because extra data is needed.
        /// </returns>
        private bool UnpackMessageId(ClientResponseContext context)
        {
            if (!context.ReadFromHeaderUnpacker())
            {
                MsgPackRpcClientProtocolsTrace.TraceEvent(MsgPackRpcClientProtocolsTrace.NeedMessageId, "Message ID is needed. {{ \"SessionID\" : {0} }}", context.SessionId);
                return(false);
            }

            try
            {
                context.MessageId = unchecked (( int )context.HeaderUnpacker.LastReadData.AsUInt32());
            }
            catch (InvalidOperationException)
            {
                this.HandleDeserializationError(
                    context,
                    "Invalid response message stream. ID must be UInt32 compatible integer.",
                    () => context.UnpackingBuffer.ToArray()
                    );
                return(context.NextProcess(context));
            }

            context.NextProcess = this.UnpackError;
            return(context.NextProcess(context));
        }
Пример #3
0
		private static ClientResponseContext CreateContext()
		{
			var context = new ClientResponseContext();
			context.ErrorBuffer = new ByteArraySegmentStream( new ArraySegment<byte>[] { new ArraySegment<byte>( new byte[] { 0xC0 } ) } );
			context.ResultBuffer = new ByteArraySegmentStream( new ArraySegment<byte>[] { new ArraySegment<byte>( new byte[] { 0xC0 } ) } );
			return context;
		}
 private void FinishReceiving(ClientResponseContext context)
 {
     context.StopWatchTimeout();
     context.Timeout -= this.OnReceiveTimeout;
     this.Manager.ReturnResponseContext(context);
     this.Manager.ReturnTransport(this);
 }
Пример #5
0
        internal bool DumpCorrupttedData(ClientResponseContext context)
        {
            if (context.BytesTransferred == 0)
            {
                context.Clear();
                return(false);
            }

            if (this.Manager.Configuration.DumpCorruptResponse)
            {
#if !SILVERLIGHT
                using (var dumpStream = OpenDumpStream(context.SessionStartedAt, context.RemoteEndPoint, context.SessionId, MessageType.Response, context.MessageId))
#else
                using (var storage = IsolatedStorageFile.GetUserStoreForApplication())
                    using (var dumpStream = OpenDumpStream(storage, context.SessionStartedAt, context.RemoteEndPoint, context.SessionId, MessageType.Response, context.MessageId))
#endif
                {
                    dumpStream.Write(context.CurrentReceivingBuffer, context.CurrentReceivingBufferOffset, context.BytesTransferred);
                    dumpStream.Flush();
                }
            }

            context.ShiftCurrentReceivingBuffer();

            return(true);
        }
        private static int?TryDetectMessageId(ClientResponseContext context)
        {
            if (context.MessageId != null)
            {
                return(context.MessageId);
            }

            using (var stream = new ByteArraySegmentStream(context.ReceivedData))
                using (var unpacker = Unpacker.Create(stream))
                {
                    if (!unpacker.Read() || !unpacker.IsArrayHeader || unpacker.LastReadData != 4)
                    {
                        // Not a response message
                        return(null);
                    }

                    if (!unpacker.Read() || !unpacker.LastReadData.IsTypeOf <Int32>().GetValueOrDefault() || unpacker.LastReadData != ( int )MessageType.Response)
                    {
                        // Not a response message or invalid message type
                        return(null);
                    }

                    if (!unpacker.Read() || !unpacker.LastReadData.IsTypeOf <Int32>().GetValueOrDefault())
                    {
                        // Invalid message ID.
                        return(null);
                    }

                    return(unpacker.LastReadData.AsInt32());
                }
        }
        public void TestClearBuffers()
        {
            var target = new ClientResponseContext();

            MakeBufferDirty(target);

            var length = target.UnpackingBuffer.Length;

            target.UnpackingBuffer.Position++;
            target.ClearBuffers();

            Assert.That(target.BoundTransport, Is.Not.Null);
            Assert.That(target.CurrentReceivingBuffer, Is.Not.Null);
            Assert.That(target.CurrentReceivingBufferOffset, Is.Not.EqualTo(0));
            Assert.That(target.ErrorBuffer, Is.Null);
            Assert.That(target.ErrorStartAt, Is.EqualTo(-1));
            Assert.That(target.HeaderUnpacker, Is.Null);
            Assert.That(target.MessageId, Is.Not.Null);
            Assert.That(target.NextProcess, Is.Not.Null);
            Assert.That(target.ReceivedData, Is.Not.Null);
            Assert.That(target.ResultBuffer, Is.Null);
            Assert.That(target.ResultStartAt, Is.EqualTo(-1));
            Assert.That(target.RootUnpacker, Is.Null);
            Assert.That(target.SessionId, Is.Not.EqualTo(0));
            Assert.That(target.SessionStartedAt, Is.Not.EqualTo(default(DateTimeOffset)));
            Assert.That(target.UnpackingBuffer, Is.Not.Null);
            Assert.That(target.UnpackingBuffer.Length, Is.LessThan(length));
        }
Пример #8
0
		/// <summary>
		///		Processes asynchronous operation completion logic.
		/// </summary>
		/// <param name="context">The response context which holds response data.</param>
		/// <param name="exception">The exception occured.</param>
		/// <param name="completedSynchronously">When operation is completed same thread as initiater then <c>true</c>; otherwise, <c>false</c>.</param>
		public void OnCompleted( ClientResponseContext context, Exception exception, bool completedSynchronously )
		{
			if ( exception != null )
			{
				base.OnError( exception, completedSynchronously );
			}
			else
			{
				var error = ErrorInterpreter.UnpackError( context );
				if ( !error.IsSuccess )
				{
					base.OnError( error.ToException(), completedSynchronously );
				}
				else
				{
					Interlocked.CompareExchange( ref this._result, new ResultHolder( Unpacking.UnpackObject( context.ResultBuffer ) ), null );
					base.Complete( completedSynchronously );
				}
			}

			var callback = this.AsyncCallback;
			if ( callback != null )
			{
				callback( this );
			}
		}
Пример #9
0
 /// <summary>
 ///		Performs protocol specific asynchronous 'Receive' operation.
 /// </summary>
 /// <param name="context">Context information.</param>
 protected sealed override void ReceiveCore(ClientResponseContext context)
 {
     if (!this.BoundSocket.ReceiveAsync(context.SocketContext))
     {
         context.SetCompletedSynchronously();
         this.OnReceived(context);
     }
 }
        private void DrainRemainingReceivedData(ClientResponseContext context)
        {
            // Process remaining binaries. This pipeline recursively call this method on other thread.
            if (!context.NextProcess(context))
            {
                // Draining was not ended. Try to take next bytes.
                this.Receive(context);
            }

            // This method must be called on other thread on the above pipeline, so exit this thread.
        }
        public void TestSetTransport_NotNull_SetAsIs()
        {
            var target = new ClientResponseContext();

            using (var manager = new NullClientTransportManager())
                using (var transport = new NullClientTransport(manager))
                {
                    target.SetTransport(transport);
                    Assert.That(target.BoundTransport, Is.SameAs(transport));
                    Assert.That(target.NextProcess, Is.EqualTo(new Func <ClientResponseContext, bool>(transport.UnpackResponseHeader)));
                }
        }
        public void TestShiftCurrentReceivingBuffer_LessThanRemains_CurrentReceivingBufferOffsetIsShifttedAndReceivedDataIsAppended()
        {
            int bytesTransferred = 13;
            var target           = new ClientResponseContext();

            target.SetBytesTransferred(bytesTransferred);
            target.ShiftCurrentReceivingBuffer();
            Assert.That(target.CurrentReceivingBufferOffset, Is.EqualTo(bytesTransferred));
            Assert.That(target.ReceivedData.Count, Is.EqualTo(1));
            Assert.That(target.ReceivedData[0].Array, Is.EqualTo(target.CurrentReceivingBuffer));
            Assert.That(target.ReceivedData[0].Offset, Is.EqualTo(0));
            Assert.That(target.ReceivedData[0].Count, Is.EqualTo(bytesTransferred));
        }
        /// <summary>
        ///		Returns the response context to the pool.
        /// </summary>
        /// <param name="context">The response to the pool.</param>
        /// <exception cref="ArgumentNullException">
        ///		<paramref name="context"/> is  <c>null</c>.
        /// </exception>
        protected internal void ReturnResponseContext(ClientResponseContext context)
        {
            if (context == null)
            {
                throw new ArgumentNullException("context");
            }

            Contract.EndContractBlock();

            context.Clear();
            context.UnboundTransport();
            this.ResponseContextPool.Return(context);
        }
        private void HandleOrphan(ClientResponseContext context)
        {
            var error = ErrorInterpreter.UnpackError(context);

            MessagePackObject?returnValue = null;

            if (error.IsSuccess)
            {
                returnValue = Unpacking.UnpackObject(context.ResultBuffer);
            }

            this.HandleOrphan(context.MessageId, context.SessionId, GetRemoteEndPoint(this.BoundSocket, context), error, returnValue);
        }
Пример #15
0
		private static ClientResponseContext CreateContext( RpcErrorMessage message )
		{
			var context = new ClientResponseContext();
			using ( var buffer = new MemoryStream() )
			using ( var packer = Packer.Create( buffer, false ) )
			{
				packer.Pack( message.Error.Identifier );
				context.ErrorBuffer = new ByteArraySegmentStream( new[] { new ArraySegment<byte>( buffer.ToArray() ) } );
				buffer.SetLength( 0 );
				packer.Pack( message.Detail );
				context.ResultBuffer = new ByteArraySegmentStream( new[] { new ArraySegment<byte>( buffer.ToArray() ) } );
			}

			return context;
		}
        /// <summary>
        ///		Returns the specified context to the <see cref="Manager"/>.
        /// </summary>
        /// <param name="context">The <see cref="ClientResponseContext"/> to be returned.</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>
        public void ReturnContext(ClientResponseContext context)
        {
            if (context == null)
            {
                throw new ArgumentNullException("context");
            }

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

            Contract.EndContractBlock();

            this.Manager.ReturnResponseContext(context);
        }
 private static void MakeBufferDirty(ClientResponseContext target)
 {
     target.SetTransport(new DummyClientTransport());
     target.SetReceivingBuffer(new byte[] { 1, 2, 3, 4 });
     target.SetBytesTransferred(1);
     target.ShiftCurrentReceivingBuffer();
     target.ErrorBuffer    = new ByteArraySegmentStream(CreateDirtyBytes());
     target.ErrorStartAt   = 1;
     target.HeaderUnpacker = Unpacker.Create(new MemoryStream());
     target.MessageId      = 1;
     target.NextProcess    = _ => true;
     target.ReceivedData.Add(new ArraySegment <byte>(new byte[] { 1, 2, 3, 4 }));
     target.ResultBuffer  = new ByteArraySegmentStream(CreateDirtyBytes());
     target.ResultStartAt = 2;
     target.RenewSessionId();
     target.UnpackingBuffer = new ByteArraySegmentStream(CreateDirtyBytes());
 }
        public void TestShiftCurrentReceivingBuffer_EqualToRemains_CurrentReceivingBufferOffsetIsInitializedAndBufferIsSwappedAndReceivedDataIsAppended()
        {
            int bytesTransferred = 13;
            var target           = new ClientResponseContext();
            var oldBuffer        = target.CurrentReceivingBuffer;

            target.SetBytesTransferred(bytesTransferred);
            target.ShiftCurrentReceivingBuffer();

            target.SetBytesTransferred(oldBuffer.Length - bytesTransferred);
            target.ShiftCurrentReceivingBuffer();
            Assert.That(target.CurrentReceivingBuffer, Is.Not.SameAs(oldBuffer));
            Assert.That(target.CurrentReceivingBufferOffset, Is.EqualTo(0));
            Assert.That(target.ReceivedData.Count, Is.EqualTo(2));
            Assert.That(target.ReceivedData[1].Array, Is.EqualTo(oldBuffer));
            Assert.That(target.ReceivedData[1].Offset, Is.EqualTo(bytesTransferred));
            Assert.That(target.ReceivedData[1].Count, Is.EqualTo(oldBuffer.Length - bytesTransferred));
        }
Пример #19
0
        protected sealed override void ReceiveCore(ClientResponseContext context)
        {
            Task.Factory.StartNew(
                () =>
            {
                try
                {
                    InProcPacket.ProcessReceive(this._inboundQueue, this._pendingPackets, context, this._linkedCancellationTokenSource.Token);
                }
                catch (OperationCanceledException)
                {
                    return;
                }

                this.OnReceived(context);
            }
                );
        }
Пример #20
0
        /// <summary>
        ///		Dispatch response message.
        /// </summary>
        /// <param name="context">Context information.</param>
        /// <returns>
        ///		<c>true</c>, if the pipeline is finished;
        ///		<c>false</c>, the pipeline is interruppted because extra data is needed.
        /// </returns>
        private bool Dispatch(ClientResponseContext context)
        {
            Contract.Assert(context.MessageId != null);

            try
            {
                Action <ClientResponseContext, Exception, bool> handler = null;
                try
                {
                    this._pendingRequestTable.TryRemove(context.MessageId.Value, out handler);
                }
                finally
                {
                    // Best effort to rescue from ThreadAbortException...
                    if (handler != null)
                    {
                        handler(context, null, context.CompletedSynchronously);
                    }
                    else
                    {
                        this.HandleOrphan(context);
                    }
                }
            }
            finally
            {
                context.ClearBuffers();
                this.OnProcessFinished();
            }

            if (context.UnpackingBuffer.Length > 0)
            {
                // Subsequent request is already arrived.
                context.NextProcess = this.UnpackResponseHeader;
                return(context.NextProcess(context));
            }
            else
            {
                // Try receive subsequent.
                return(true);
            }
        }
        public void TestConstructor_AllPropertiesAreInitialized()
        {
            var target = new ClientResponseContext();

            Assert.That(target.BoundTransport, Is.Null);
            Assert.That(target.CurrentReceivingBuffer, Is.Not.Null);
            Assert.That(target.CurrentReceivingBufferOffset, Is.EqualTo(0));
            Assert.That(target.ErrorBuffer, Is.Null);
            Assert.That(target.ErrorStartAt, Is.EqualTo(-1));
            Assert.That(target.HeaderUnpacker, Is.Null);
            Assert.That(target.MessageId, Is.Null);
            Assert.That(target.NextProcess, Is.Null);
            Assert.That(target.ReceivedData, Is.Not.Null);
            Assert.That(target.ResultBuffer, Is.Null);
            Assert.That(target.ResultStartAt, Is.EqualTo(-1));
            Assert.That(target.RootUnpacker, Is.Null);
            Assert.That(target.SessionId, Is.EqualTo(0));
            Assert.That(target.SessionStartedAt, Is.EqualTo(default(DateTimeOffset)));
            Assert.That(target.UnpackingBuffer, Is.Null);
        }
        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>
		///		Unpack response message array header.
		/// </summary>
		/// <param name="context">Context information.</param>
		/// <returns>
		///		<c>true</c>, if the pipeline is finished;
		///		<c>false</c>, the pipeline is interruppted because extra data is needed.
		/// </returns>
		internal bool UnpackResponseHeader( ClientResponseContext context )
		{
			Contract.Assert( context != null );

			if ( context.RootUnpacker == null )
			{
				context.UnpackingBuffer = new ByteArraySegmentStream( context.ReceivedData );
				context.RootUnpacker = Unpacker.Create( context.UnpackingBuffer, false );
				context.RenewSessionId();
			}

			if ( !context.ReadFromRootUnpacker() )
			{
				MsgPackRpcClientProtocolsTrace.TraceEvent( MsgPackRpcClientProtocolsTrace.NeedRequestHeader, "Array header is needed. {{ \"SessionID\" : {0} }}", context.SessionId );
				return false;
			}

			if ( !context.RootUnpacker.IsArrayHeader )
			{
				this.HandleDeserializationError( context, "Invalid response message stream. Message must be array.", () => context.UnpackingBuffer.ToArray() );
				return context.NextProcess( context );
			}

			if ( context.RootUnpacker.ItemsCount != 4 )
			{
				this.HandleDeserializationError(
					context,
					String.Format(
						CultureInfo.CurrentCulture,
						"Invalid response message stream. Message must be valid size array. Actual size is {0}.",
						context.RootUnpacker.ItemsCount
					),
					() => context.UnpackingBuffer.ToArray()
				);
				return context.NextProcess( context );
			}

			context.HeaderUnpacker = context.RootUnpacker.ReadSubtree();
			context.NextProcess = UnpackMessageType;
			return context.NextProcess( context );
		}
Пример #24
0
        /// <summary>
        ///		Unpack response message array header.
        /// </summary>
        /// <param name="context">Context information.</param>
        /// <returns>
        ///		<c>true</c>, if the pipeline is finished;
        ///		<c>false</c>, the pipeline is interruppted because extra data is needed.
        /// </returns>
        internal bool UnpackResponseHeader(ClientResponseContext context)
        {
            Contract.Assert(context != null);

            if (context.RootUnpacker == null)
            {
                context.UnpackingBuffer = new ByteArraySegmentStream(context.ReceivedData);
                context.RootUnpacker    = Unpacker.Create(context.UnpackingBuffer, false);
                context.RenewSessionId();
            }

            if (!context.ReadFromRootUnpacker())
            {
                MsgPackRpcClientProtocolsTrace.TraceEvent(MsgPackRpcClientProtocolsTrace.NeedRequestHeader, "Array header is needed. {{ \"SessionID\" : {0} }}", context.SessionId);
                return(false);
            }

            if (!context.RootUnpacker.IsArrayHeader)
            {
                this.HandleDeserializationError(context, "Invalid response message stream. Message must be array.", () => context.UnpackingBuffer.ToArray());
                return(context.NextProcess(context));
            }

            if (context.RootUnpacker.ItemsCount != 4)
            {
                this.HandleDeserializationError(
                    context,
                    String.Format(
                        CultureInfo.CurrentCulture,
                        "Invalid response message stream. Message must be valid size array. Actual size is {0}.",
                        context.RootUnpacker.ItemsCount
                        ),
                    () => context.UnpackingBuffer.ToArray()
                    );
                return(context.NextProcess(context));
            }

            context.HeaderUnpacker = context.RootUnpacker.ReadSubtree();
            context.NextProcess    = UnpackMessageType;
            return(context.NextProcess(context));
        }
Пример #25
0
        /// <summary>
        ///		Unpack result part on response message.
        /// </summary>
        /// <param name="context">Context information.</param>
        /// <returns>
        ///		<c>true</c>, if the pipeline is finished;
        ///		<c>false</c>, the pipeline is interruppted because extra data is needed.
        /// </returns>
        private bool UnpackResult(ClientResponseContext context)
        {
            Contract.Assert(context.UnpackingBuffer.CanSeek);
            if (context.ResultStartAt == -1)
            {
                context.ResultStartAt = context.UnpackingBuffer.Position;
            }

            var skipped = context.SkipResultSegment();

            if (skipped == null)
            {
                MsgPackRpcClientProtocolsTrace.TraceEvent(MsgPackRpcClientProtocolsTrace.NeedResult, "Result value is needed. {{ \"SessionID\" : {0} }}", context.SessionId);
                return(false);
            }

            context.ResultBuffer = new ByteArraySegmentStream(context.UnpackingBuffer.GetBuffer(context.ResultStartAt, context.UnpackingBuffer.Position - context.ResultStartAt));
            context.NextProcess  = this.Dispatch;

            return(context.NextProcess(context));
        }
Пример #26
0
        /// <summary>
        ///		Unpack Message Type part on response message.
        /// </summary>
        /// <param name="context">Context information.</param>
        /// <returns>
        ///		<c>true</c>, if the pipeline is finished;
        ///		<c>false</c>, the pipeline is interruppted because extra data is needed.
        /// </returns>
        private bool UnpackMessageType(ClientResponseContext context)
        {
            if (!context.ReadFromHeaderUnpacker())
            {
                MsgPackRpcClientProtocolsTrace.TraceEvent(MsgPackRpcClientProtocolsTrace.NeedMessageType, "Message Type is needed. {{ \"SessionID\" : {0} }}", context.SessionId);
                return(false);
            }

            int numericType;

            try
            {
                numericType = context.HeaderUnpacker.LastReadData.AsInt32();
            }
            catch (InvalidOperationException)
            {
                this.HandleDeserializationError(context, "Invalid response message stream. Message Type must be Int32 compatible integer.", () => context.UnpackingBuffer.ToArray());
                return(context.NextProcess(context));
            }

            MessageType type = ( MessageType )numericType;

            if (type != MessageType.Response)
            {
                this.HandleDeserializationError(
                    context,
                    String.Format(CultureInfo.CurrentCulture, "Unknown message type '{0:x8}'", numericType),
                    () => context.UnpackingBuffer.ToArray()
                    );
                return(context.NextProcess(context));
            }

            context.NextProcess = this.UnpackMessageId;

            return(context.NextProcess(context));
        }
 protected override void ReceiveCore(ClientResponseContext context)
 {
     throw new NotImplementedException();
 }
		internal bool DumpCorrupttedData( ClientResponseContext context )
		{
			if ( context.BytesTransferred == 0 )
			{
				context.Clear();
				return false;
			}

			if ( this.Manager.Configuration.DumpCorruptResponse )
			{
#if !SILVERLIGHT
				using ( var dumpStream = OpenDumpStream( context.SessionStartedAt, context.RemoteEndPoint, context.SessionId, MessageType.Response, context.MessageId ) )
#else
				using( var storage = IsolatedStorageFile.GetUserStoreForApplication() )
				using( var dumpStream = OpenDumpStream( storage, context.SessionStartedAt, context.RemoteEndPoint, context.SessionId, MessageType.Response, context.MessageId ) )
#endif
				{
					dumpStream.Write( context.CurrentReceivingBuffer, context.CurrentReceivingBufferOffset, context.BytesTransferred );
					dumpStream.Flush();
				}
			}

			context.ShiftCurrentReceivingBuffer();

			return true;
		}
        /// <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>
 ///		Performs protocol specific asynchronous 'Receive' operation.
 /// </summary>
 /// <param name="context">Context information.</param>
 protected abstract void ReceiveCore(ClientResponseContext context);
Пример #31
0
		/// <summary>
		///		Performs protocol specific asynchronous 'Receive' operation.
		/// </summary>
		/// <param name="context">Context information.</param>
		protected sealed override void ReceiveCore( ClientResponseContext context )
		{
			if ( !this.BoundSocket.ReceiveFromAsync( context.SocketContext ) )
			{
				context.SetCompletedSynchronously();
				this.OnReceived( context );
			}
		}
Пример #32
0
		protected sealed override void ReceiveCore( ClientResponseContext context )
		{
			Task.Factory.StartNew(
				() =>
				{
					try
					{
						InProcPacket.ProcessReceive( this._inboundQueue, this._pendingPackets, context, this._linkedCancellationTokenSource.Token );
					}
					catch ( OperationCanceledException )
					{
						return;
					}

					this.OnReceived( context );
				}
			);
		}
 /// <summary>
 ///		Performs protocol specific asynchronous 'Receive' operation.
 /// </summary>
 /// <param name="context">Context information.</param>
 protected override void ReceiveCore(ClientResponseContext context)
 {
     this.OnReceived(context);
 }
		/// <summary>
		///		Unpack Message Type part on response message.
		/// </summary>
		/// <param name="context">Context information.</param>
		/// <returns>
		///		<c>true</c>, if the pipeline is finished;
		///		<c>false</c>, the pipeline is interruppted because extra data is needed.
		/// </returns>
		private bool UnpackMessageType( ClientResponseContext context )
		{
			if ( !context.ReadFromHeaderUnpacker() )
			{
				MsgPackRpcClientProtocolsTrace.TraceEvent( MsgPackRpcClientProtocolsTrace.NeedMessageType, "Message Type is needed. {{ \"SessionID\" : {0} }}", context.SessionId );
				return false;
			}

			int numericType;
			try
			{
				numericType = context.HeaderUnpacker.LastReadData.AsInt32();
			}
			catch ( InvalidOperationException )
			{
				this.HandleDeserializationError( context, "Invalid response message stream. Message Type must be Int32 compatible integer.", () => context.UnpackingBuffer.ToArray() );
				return context.NextProcess( context );
			}

			MessageType type = ( MessageType )numericType;
			if ( type != MessageType.Response )
			{
				this.HandleDeserializationError(
					context,
					String.Format( CultureInfo.CurrentCulture, "Unknown message type '{0:x8}'", numericType ),
					() => context.UnpackingBuffer.ToArray()
				);
				return context.NextProcess( context );
			}

			context.NextProcess = this.UnpackMessageId;

			return context.NextProcess( context );
		}
 private void HandleDeserializationError(ClientResponseContext context, string message, Func <byte[]> invalidRequestHeaderProvider)
 {
     this.HandleDeserializationError(context, context.MessageId, new RpcErrorMessage(RpcError.RemoteRuntimeError, "Invalid stream.", message), message, invalidRequestHeaderProvider);
 }
Пример #36
0
		/// <summary>
		///		Performs protocol specific asynchronous 'Receive' operation.
		/// </summary>
		/// <param name="context">Context information.</param>
		protected override void ReceiveCore( ClientResponseContext context )
		{
			this.OnReceived( context );
		}
Пример #37
0
		/// <summary>
		///		Unpacks <see cref="RpcErrorMessage"/> from stream in the specified context.
		/// </summary>
		/// <param name="context"><see cref="ClientResponseContext"/> which stores serialized error.</param>
		/// <returns>An unpacked <see cref="RpcErrorMessage"/>.</returns>
		internal static RpcErrorMessage UnpackError( ClientResponseContext context )
		{
			Contract.Assert( context != null );
			Contract.Assert( context.ErrorBuffer != null );
			Contract.Assert( context.ErrorBuffer.Length > 0 );
			Contract.Assert( context.ResultBuffer != null );
			Contract.Assert( context.ResultBuffer.Length > 0 );

			MessagePackObject error;
			try
			{
				error = Unpacking.UnpackObject( context.ErrorBuffer );
			}
			catch ( UnpackException )
			{
				error = new MessagePackObject( context.ErrorBuffer.GetBuffer().SelectMany( segment => segment.AsEnumerable() ).ToArray() );
			}

			if ( error.IsNil )
			{
				return RpcErrorMessage.Success;
			}

			bool isUnknown = false;
			RpcError errorIdentifier;
			if ( error.IsTypeOf<string>().GetValueOrDefault() )
			{
				var asString = error.AsString();
				errorIdentifier = RpcError.FromIdentifier( asString, null );
				// Check if the error is truely Unexpected error.
				isUnknown = errorIdentifier.ErrorCode == RpcError.Unexpected.ErrorCode && asString != RpcError.Unexpected.Identifier;
			}
			else if ( error.IsTypeOf<int>().GetValueOrDefault() )
			{
				errorIdentifier = RpcError.FromIdentifier( null, error.AsInt32() );
			}
			else
			{
				errorIdentifier = RpcError.Unexpected;
				isUnknown = true;
			}

			MessagePackObject detail;
			if ( context.ResultBuffer.Length == 0 )
			{
				detail = MessagePackObject.Nil;
			}
			else
			{
				try
				{
					detail = Unpacking.UnpackObject( context.ResultBuffer );
				}
				catch ( UnpackException )
				{
					detail = new MessagePackObject( context.ResultBuffer.GetBuffer().SelectMany( segment => segment.AsEnumerable() ).ToArray() );
				}
			}

			if ( isUnknown )
			{
				// Unknown error, the error should contain original Error field as message.
				if ( detail.IsNil )
				{
					return new RpcErrorMessage( errorIdentifier, error.AsString(), null );
				}
				else
				{
					var details = new MessagePackObjectDictionary( 2 );
					details[ RpcException.MessageKeyUtf8 ] = error;
					details[ RpcException.DebugInformationKeyUtf8 ] = detail;
					return new RpcErrorMessage( errorIdentifier, new MessagePackObject( details, true ) );
				}
			}
			else
			{
				return new RpcErrorMessage( errorIdentifier, detail );
			}
		}
		/// <summary>
		///		Unpack Message ID part on response message.
		/// </summary>
		/// <param name="context">Context information.</param>
		/// <returns>
		///		<c>true</c>, if the pipeline is finished;
		///		<c>false</c>, the pipeline is interruppted because extra data is needed.
		/// </returns>
		private bool UnpackMessageId( ClientResponseContext context )
		{
			if ( !context.ReadFromHeaderUnpacker() )
			{
				MsgPackRpcClientProtocolsTrace.TraceEvent( MsgPackRpcClientProtocolsTrace.NeedMessageId, "Message ID is needed. {{ \"SessionID\" : {0} }}", context.SessionId );
				return false;
			}

			try
			{
				context.MessageId = unchecked( ( int )context.HeaderUnpacker.LastReadData.AsUInt32() );
			}
			catch ( InvalidOperationException )
			{
				this.HandleDeserializationError(
					context,
					"Invalid response message stream. ID must be UInt32 compatible integer.",
					() => context.UnpackingBuffer.ToArray()
				);
				return context.NextProcess( context );
			}

			context.NextProcess = this.UnpackError;
			return context.NextProcess( context );
		}
Пример #39
0
		/// <summary>
		///		Returns the response context to the pool.
		/// </summary>
		/// <param name="context">The response to the pool.</param>
		/// <exception cref="ArgumentNullException">
		///		<paramref name="context"/> is  <c>null</c>.
		/// </exception>
		protected internal void ReturnResponseContext( ClientResponseContext context )
		{
			if ( context == null )
			{
				throw new ArgumentNullException( "context" );
			}

			Contract.EndContractBlock();

			context.Clear();
			context.UnboundTransport();
			this.ResponseContextPool.Return( context );
		}
		/// <summary>
		///		Unpack result part on response message.
		/// </summary>
		/// <param name="context">Context information.</param>
		/// <returns>
		///		<c>true</c>, if the pipeline is finished;
		///		<c>false</c>, the pipeline is interruppted because extra data is needed.
		/// </returns>
		private bool UnpackResult( ClientResponseContext context )
		{
			Contract.Assert( context.UnpackingBuffer.CanSeek );
			if ( context.ResultStartAt == -1 )
			{
				context.ResultStartAt = context.UnpackingBuffer.Position;
			}

			var skipped = context.SkipResultSegment();
			if ( skipped == null )
			{
				MsgPackRpcClientProtocolsTrace.TraceEvent( MsgPackRpcClientProtocolsTrace.NeedResult, "Result value is needed. {{ \"SessionID\" : {0} }}", context.SessionId );
				return false;
			}

			context.ResultBuffer = new ByteArraySegmentStream( context.UnpackingBuffer.GetBuffer( context.ResultStartAt, context.UnpackingBuffer.Position - context.ResultStartAt ) );
			context.NextProcess = this.Dispatch;

			return context.NextProcess( context );
		}
		/// <summary>
		///		Dispatch response message.
		/// </summary>
		/// <param name="context">Context information.</param>
		/// <returns>
		///		<c>true</c>, if the pipeline is finished;
		///		<c>false</c>, the pipeline is interruppted because extra data is needed.
		/// </returns>
		private bool Dispatch( ClientResponseContext context )
		{
			Contract.Assert( context.MessageId != null );

			try
			{
				Action<ClientResponseContext, Exception, bool> handler = null;
				try
				{
					this._pendingRequestTable.TryRemove( context.MessageId.Value, out handler );
				}
				finally
				{
					// Best effort to rescue from ThreadAbortException...
					if ( handler != null )
					{
						handler( context, null, context.CompletedSynchronously );
					}
					else
					{
						this.HandleOrphan( context );
					}
				}
			}
			finally
			{
				context.ClearBuffers();
				this.OnProcessFinished();
			}

			if ( context.UnpackingBuffer.Length > 0 )
			{
				// Subsequent request is already arrived.
				context.NextProcess = this.UnpackResponseHeader;
				return context.NextProcess( context );
			}
			else
			{
				// Try receive subsequent.
				return true;
			}
		}
 private static bool InvalidFlow(ClientResponseContext context)
 {
     throw new InvalidOperationException("Invalid state transition.");
 }
Пример #43
0
		private static bool InvalidFlow( ClientResponseContext context )
		{
			throw new InvalidOperationException( "Invalid state transition." );
		}