/// <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); } }
/// <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)); }
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); }
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)); }
/// <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 ); } }
/// <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); }
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)); }
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> /// 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 ); }
/// <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)); }
/// <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> /// 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);
/// <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 ); } }
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); }
/// <summary> /// Performs protocol specific asynchronous 'Receive' operation. /// </summary> /// <param name="context">Context information.</param> protected override void ReceiveCore( ClientResponseContext context ) { this.OnReceived( context ); }
/// <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 ); }
/// <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."); }
private static bool InvalidFlow( ClientResponseContext context ) { throw new InvalidOperationException( "Invalid state transition." ); }