Beispiel #1
0
        /// <inheritdoc />
        public async Task <IMessage> ReadMessageAsync(CancellationToken cancellationToken, int timeout = Timeout.Infinite)
        {
            var headerBytes = new byte[6];

            using (var cts = cancellationToken.AddTimeout(timeout))
            {
                await this.sslStream.ReadAsync(headerBytes, 0, headerBytes.Length, cts.Token)
                .HandleTimeout(cts.Token).ConfigureAwait(false);
            }

            var type = IPAddress.NetworkToHostOrder(BitConverter.ToInt16(headerBytes, 0));
            var size = IPAddress.NetworkToHostOrder(BitConverter.ToInt32(headerBytes, 2));

            var messageBytes = new byte[size];

            using (var cts = cancellationToken.AddTimeout(timeout))
            {
                await this.sslStream.ReadAsync(messageBytes, 0, size, cts.Token)
                .HandleTimeout(cts.Token).ConfigureAwait(false);
            }

            if (type == (int)MessageType.UDPTunnel)
            {
                return(new UDPTunnel.Builder
                {
                    Packet = ByteString.CopyFrom(messageBytes)
                }.Build());
            }
            else
            {
                return(this.messageFactory.Deserialize((MessageType)type, ByteString.CopyFrom(messageBytes)));
            }
        }
Beispiel #2
0
        public async Task <GrpcResponseEnvelope <TResponse> > Execute <TRequest, TResponse>(TRequest request, CancellationToken cancellationToken)
        {
            if (request == null)
            {
                throw new ArgumentNullException();
            }

            // timeout
            cancellationToken = cancellationToken.AddTimeout(_configuration.TimeoutMs);

            // ch info
            var chInfo = _cqrsAdapter.ToCqrsChannelInfo().FirstOrDefault(x => x.ReqType == request.GetType() && x.RspType == typeof(TResponse));

            if (chInfo == null)
            {
                throw new ArgumentException("Invaid request type.");
            }

            // calll
            var callMethod = GetType().GetMethods(BindingFlags.Instance | BindingFlags.NonPublic)
                             .First(x => x.Name == nameof(GrpcCqrsClient.CallUnaryMethodAsync))
                             .MakeGenericMethod(chInfo.ReqType, chInfo.RspType, chInfo.ChReqType, chInfo.ChRspType, chInfo.ChRspEnvType);
            var execTask = callMethod.Invoke(this, new object[] { request, default(CancellationToken) }) as Task <GrpcResponseEnvelope <TResponse> >;
            var result   = await execTask;

            return(result);
        }
Beispiel #3
0
        public static async Task <InitializationResult <AuthenticatedStream> > RegisterWithServerAsync(
            Stream serverStream,
            byte[] presharedKey,
            Guid ownGuid,
            Guid serverGuid,
            IAuthenticatedConnectionFactory authenticatedConnectionFactory,
            X509Certificate2 clientCertificate,
            X509Certificate serverCertificate,
            ICryptographicService otp,
            CancellationToken token)
        {
            InitializationResult <AuthenticatedStream> From(CommunicationResult res) => From <AuthenticatedStream>(res);

            if (!otp.CanEncrypt)
            {
                throw new ArgumentException("otp needs to be able to encrypt");
            }
            token = token.AddTimeout(DefaultTimeout);

            await serverStream.WriteSafelyAsync(presharedKey, token);

            var serverGuidResult = await serverStream.ReceiveGuidSafelyAsync(token);

            if (!serverGuidResult.Successful)
            {
                return(From(serverGuidResult));
            }
            if (!serverGuidResult.Result.Equals(serverGuid))
            {
                return(new InitializationResult <AuthenticatedStream>
                {
                    Successful = false,
                    Error = new InitializationError
                    {
                        ErrorType = InitializationErrorType.Identification,
                        Message = $"Expected server to be '{serverGuid}', but instead found '{serverGuidResult.Result}'",
                    },
                });
            }
            await serverStream.WriteSafelyAsync(
                ownGuid,
                (int)InitiationMode.Otp,
                token);

            var exportCertificate    = clientCertificate.Export(X509ContentType.Cert);
            var encryptedCertificate = otp.Encrypt(exportCertificate);
            await serverStream.WriteSafelyAsync(
                (int)CommunicationData.PublicKey,
                encryptedCertificate.Length,
                encryptedCertificate,
                token);

            return(await EstablishEncryptedCommunication(false, serverGuid, authenticatedConnectionFactory,
                                                         serverStream, token));
        }
Beispiel #4
0
        /// <summary>
        /// Write a message to the SSL stream
        /// </summary>
        /// <param name="type">Type of message</param>
        /// <param name="messageBytes">Byte array of serialized message</param>
        /// <param name="cancellationToken">The token to monitor for cancellation requests</param>
        /// <returns>Empty task</returns>
        private async Task WriteMessageAsync(MessageType type, byte[] messageBytes, CancellationToken cancellationToken)
        {
            var typeBytes = BitConverter.GetBytes(IPAddress.HostToNetworkOrder((short)type));
            var sizeBytes = BitConverter.GetBytes(IPAddress.HostToNetworkOrder(messageBytes.Length));

            await this.writeSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false);

            using (var cts = cancellationToken.AddTimeout(WriteTimeout))
            {
                await this.sslStream.WriteAsync(typeBytes, 0, typeBytes.Length, cts.Token)
                .HandleTimeout(cts.Token).ConfigureAwait(false);

                await this.sslStream.WriteAsync(sizeBytes, 0, sizeBytes.Length, cts.Token)
                .HandleTimeout(cts.Token).ConfigureAwait(false);

                await this.sslStream.WriteAsync(messageBytes, 0, messageBytes.Length, cts.Token)
                .HandleTimeout(cts.Token).ConfigureAwait(false);
            }

            this.writeSemaphore.Release();
        }
Beispiel #5
0
        /// <summary>
        /// Waits for a release signal that indicates that this activity has been executed
        /// successfully in the background.
        /// </summary>
        /// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
        /// <returns>A Task that represents the asynchronous operation.</returns>
        public async STT.Task WaitForCompleteAsync(CancellationToken cancellationToken)
        {
            if (_finished)
            {
                return;
            }

            _waitingThreadId = Thread.CurrentThread.ManagedThreadId;

            var indexingActivity = this as IndexingActivityBase;

            SnTrace.IndexQueue.Write("IAQ: A{0} blocks the T{1}", indexingActivity?.Id, _waitingThreadId);

            if (Debugger.IsAttached)
            {
                // in debug mode wait without a timeout
                await _finishSignal.WaitAsync(cancellationToken).ConfigureAwait(false);
            }
            else
            {
                try
                {
                    var timeOut = TimeSpan.FromSeconds(Configuration.Indexing.IndexingActivityTimeoutInSeconds);

                    await _finishSignal.WaitAsync(cancellationToken.AddTimeout(timeOut)).ConfigureAwait(false);
                }
                catch (OperationCanceledException)
                {
                    var message = indexingActivity != null
                        ? $"IndexingActivity is timed out. Id: {indexingActivity.Id}, Type: {indexingActivity.ActivityType}. " +
                                  $"Max task id and exceptions: {IndexManager.DistributedIndexingActivityQueue.GetCurrentCompletionState()}"
                        : "Activity is not finishing on a timely manner";

                    throw new ApplicationException(message);
                }
            }
        }
Beispiel #6
0
        internal async Task <IncomingMessage> PerformRequestAsync(CancellationToken cancellationToken)
        {
            int retryCounter = 0;

            IncomingMessage reply;
            var             reassembler = new MessageReassembler(ctrl, this);


            while (retryCounter++ < retries)
            {
                // send message
                if (await outgoingMsg.SendAsync().ConfigureAwait(false))
                {
                    // need to have a timeout to cancel the process task otherwise it may end up waiting forever for this to return
                    // because we have an external cancellation token and the above timeout cancellation token, need to combine both
                    reply = await reassembler.ProcessAsync(cancellationToken.AddTimeout(waitRetryTimeout)).ConfigureAwait(false);

                    if (reply != null)
                    {
                        return(reply);
                    }
                }
                else
                {
                    // send failed
                    Debug.WriteLine("SEND FAILED...");
                }

                // something went wrong, retry with a progressive back-off strategy
                await Task.Delay(200 *retryCounter);
            }

            Debug.WriteLine("exceeded attempts count...");

            return(null);
        }
        /// <summary>
        /// Essential Rx method. Drives state machine by reading data and processing it. This works in
        /// conjunction with NotificationThreadWorker [Tx].
        /// </summary>
        internal async Task <IncomingMessage> ProcessAsync(CancellationToken cancellationToken)
        {
            int count;
            int bytesRead;

            try
            {
                while (true)
                {
                    if (cancellationToken.IsCancellationRequested)
                    {
                        // cancellation requested

                        Debug.WriteLine("cancel token");

                        return(GetCompleteMessage());
                    }

                    switch (_state)
                    {
                    case ReceiveState.Initialize:


                        _rawPos = 0;

                        _messageBase        = new MessageBase();
                        _messageBase.Header = new Packet();

                        _messageRaw        = new MessageRaw();
                        _messageRaw.Header = _parent.CreateConverter().Serialize(_messageBase.Header);

                        _state = ReceiveState.WaitingForHeader;
                        DebuggerEventSource.Log.WireProtocolReceiveState(_state);
                        break;

                    case ReceiveState.WaitingForHeader:
                        count = _messageRaw.Header.Length - _rawPos;

                        Debug.WriteLine("WaitingForHeader");

                        // need to have a timeout to cancel the read task otherwise it may end up waiting forever for this to return
                        // because we have an external cancellation token and the above timeout cancellation token, need to combine both

                        bytesRead = await _parent.ReadBufferAsync(_messageRaw.Header, _rawPos, count, request.waitRetryTimeout, cancellationToken.AddTimeout(request.waitRetryTimeout));

                        _rawPos += bytesRead;

                        // sanity check
                        if (bytesRead != 32)
                        {
                            // doesn't look like a header, better restart
                            _state = ReceiveState.Initialize;
                            break;
                        }

                        while (_rawPos > 0)
                        {
                            int flag_Debugger = ValidMarker(markerDebugger);
                            int flag_Packet   = ValidMarker(markerPacket);

                            if (flag_Debugger == 1 || flag_Packet == 1)
                            {
                                _state = ReceiveState.ReadingHeader;
                                DebuggerEventSource.Log.WireProtocolReceiveState(_state);
                                break;
                            }

                            if (flag_Debugger == 0 || flag_Packet == 0)
                            {
                                break;     // Partial match.
                            }

                            _parent.App.SpuriousCharacters(_messageRaw.Header, 0, 1);

                            Array.Copy(_messageRaw.Header, 1, _messageRaw.Header, 0, --_rawPos);
                        }
                        break;

                    case ReceiveState.ReadingHeader:
                        count = _messageRaw.Header.Length - _rawPos;

                        Debug.WriteLine("ReadingHeader");

                        // need to have a timeout to cancel the read task otherwise it may end up waiting forever for this to return
                        // because we have an external cancellation token and the above timeout cancellation token, need to combine both

                        bytesRead = await _parent.ReadBufferAsync(_messageRaw.Header, _rawPos, count, request.waitRetryTimeout, cancellationToken.AddTimeout(request.waitRetryTimeout));

                        _rawPos += bytesRead;

                        if (bytesRead != count)
                        {
                            break;
                        }

                        _state = ReceiveState.CompleteHeader;
                        DebuggerEventSource.Log.WireProtocolReceiveState(_state);
                        break;

                    case ReceiveState.CompleteHeader:
                        try
                        {
                            Debug.WriteLine("CompleteHeader");

                            _parent.CreateConverter().Deserialize(_messageBase.Header, _messageRaw.Header);

                            if (VerifyHeader() == true)
                            {
                                Debug.WriteLine("CompleteHeader, header OK");

                                bool fReply = (_messageBase.Header.Flags & Flags.c_Reply) != 0;

                                DebuggerEventSource.Log.WireProtocolRxHeader(_messageBase.Header.CrcHeader, _messageBase.Header.CrcData, _messageBase.Header.Cmd, _messageBase.Header.Flags, _messageBase.Header.Seq, _messageBase.Header.SeqReply, _messageBase.Header.Size);

                                if (_messageBase.Header.Size != 0)
                                {
                                    _messageRaw.Payload = new byte[_messageBase.Header.Size];
                                    //reuse m_rawPos for position in header to read.
                                    _rawPos = 0;

                                    _state = ReceiveState.ReadingPayload;
                                    DebuggerEventSource.Log.WireProtocolReceiveState(_state);
                                    break;
                                }
                                else
                                {
                                    _state = ReceiveState.CompletePayload;
                                    DebuggerEventSource.Log.WireProtocolReceiveState(_state);
                                    break;
                                }
                            }

                            Debug.WriteLine("CompleteHeader, header not valid");
                        }
                        //catch (ThreadAbortException)
                        //{
                        //    throw;
                        //}
                        catch (Exception e)
                        {
                            Debug.WriteLine("Fault at payload deserialization:\n\n{0}", e.ToString());
                        }

                        _state = ReceiveState.Initialize;
                        DebuggerEventSource.Log.WireProtocolReceiveState(_state);

                        if ((_messageBase.Header.Flags & Flags.c_NonCritical) == 0)
                        {
                            // FIXME
                            // evaluate the purpose of this reply back to the NanoFramework device, the nanoCLR doesn't seem to have to handle this. In the end it looks like this does have any real purpose and will only be wasting CPU.
                            //await IncomingMessage.ReplyBadPacketAsync(m_parent, Flags.c_BadHeader);
                            return(GetCompleteMessage());
                        }

                        break;

                    case ReceiveState.ReadingPayload:
                        count = _messageRaw.Payload.Length - _rawPos;

                        Debug.WriteLine("ReadingPayload");

                        // need to have a timeout to cancel the read task otherwise it may end up waiting forever for this to return
                        // because we have an external cancellation token and the above timeout cancellation token, need to combine both

                        bytesRead = await _parent.ReadBufferAsync(_messageRaw.Payload, _rawPos, count, request.waitRetryTimeout, cancellationToken.AddTimeout(request.waitRetryTimeout));

                        _rawPos += bytesRead;

                        if (bytesRead != count)
                        {
                            break;
                        }

                        _state = ReceiveState.CompletePayload;
                        DebuggerEventSource.Log.WireProtocolReceiveState(_state);
                        break;

                    case ReceiveState.CompletePayload:
                        Debug.WriteLine("CompletePayload");

                        if (VerifyPayload() == true)
                        {
                            Debug.WriteLine("CompletePayload payload OK");

                            try
                            {
                                bool fReply = (_messageBase.Header.Flags & Flags.c_Reply) != 0;

                                if ((_messageBase.Header.Flags & Flags.c_NACK) != 0)
                                {
                                    _messageRaw.Payload = null;
                                }

                                if (await ProcessMessage(GetCompleteMessage(), fReply, cancellationToken))
                                {
                                    DebuggerEventSource.Log.WireProtocolReceiveState(_state);

                                    //Debug.WriteLine("*** leaving reassembler");

                                    return(GetCompleteMessage());
                                }
                                else
                                {
                                    // this is not the message we were waiting
                                    // FIXME
                                }
                                //m_parent.App.ProcessMessage(this.GetCompleteMessage(), fReply);

                                //m_state = ReceiveState.Initialize;
                                //return;
                            }
                            //catch (ThreadAbortException)
                            //{
                            //    throw;
                            //}
                            catch (Exception e)
                            {
                                Debug.WriteLine("Fault at payload deserialization:\n\n{0}", e.ToString());
                            }
                        }
                        else
                        {
                            Debug.WriteLine("CompletePayload payload not valid");
                        }

                        _state = ReceiveState.Initialize;
                        DebuggerEventSource.Log.WireProtocolReceiveState(_state);

                        if ((_messageBase.Header.Flags & Flags.c_NonCritical) == 0)
                        {
                            // FIXME
                            // evaluate the purpose of this reply back to the NanoFramework device, the nanoCLR doesn't seem to have to handle this. In the end it looks like this does have any real purpose and will only be wasting CPU.
                            await IncomingMessage.ReplyBadPacketAsync(_parent, Flags.c_BadPayload, cancellationToken);

                            return(GetCompleteMessage());
                        }

                        break;
                    }
                }
            }
            catch (Exception ex)
            {
                _state = ReceiveState.Initialize;
                DebuggerEventSource.Log.WireProtocolReceiveState(_state);
                Debug.WriteLine($"*** EXCEPTION IN STATE MACHINE***:\r\n{ex.Message} \r\n{ex.StackTrace}");
                throw;
            }

            Debug.WriteLine("??????? leaving reassembler");
            return(GetCompleteMessage());
        }
Beispiel #8
0
        public async Task <byte[]> ReadBufferAsync(uint bytesToRead, TimeSpan waiTimeout, CancellationToken cancellationToken)
        {
            // device must be connected
            if (EventHandlerForSerialDevice.Current.IsDeviceConnected)
            {
                // serial works as a "single channel" so we can only TX or RX,
                // meaning that access to the resource has to be protected with a semephore
                await semaphore.WaitAsync();

                // create a stream reader with serial device InputStream, if there isn't one already
                if (inputStreamReader == null)
                {
                    inputStreamReader = new DataReader(EventHandlerForSerialDevice.Current.Device.InputStream);
                }

                try
                {
                    // need to have a timeout to cancel the read task otherwise it may end up waiting forever for this to return
                    // because we have an external cancellation token and the above timeout cancellation token, need to combine both
                    Task <UInt32> loadAsyncTask = inputStreamReader.LoadAsync(bytesToRead).AsTask(cancellationToken.AddTimeout(waiTimeout));

                    // get how many bytes are available to read
                    uint bytesRead = await loadAsyncTask;

                    byte[] readBuffer = new byte[bytesToRead];
                    inputStreamReader.ReadBytes(readBuffer);

                    return(readBuffer);
                }
                catch (TaskCanceledException)
                {
                    // this is expected to happen, don't do anything with it
                }
                catch (NullReferenceException)
                {
                    // this is expected to happen when there is anything to read, don't do anything with it
                }
                catch (Exception ex)
                {
                    Debug.WriteLine($"SendRawBufferAsync-Serial-Exception occurred: {ex.Message}\r\n {ex.StackTrace}");
                }
                finally
                {
                    // relase serial device semaphore
                    semaphore.Release();

                    // detach read buffer
                    inputStreamReader.DetachBuffer();
                }
            }
            else
            {
                // FIXME
                // NotifyDeviceNotConnected
                Debug.WriteLine("NotifyDeviceNotConnected");
            }

            // return empty byte array
            return(new byte[0]);
        }
Beispiel #9
0
        public async Task <uint> SendBufferAsync(byte[] buffer, TimeSpan waiTimeout, CancellationToken cancellationToken)
        {
            uint bytesWritten = 0;

            // device must be connected
            if (EventHandlerForSerialDevice.Current.IsDeviceConnected)
            {
                // create a stream writer with serial device OutputStream, if there isn't one already
                if (outputStreamWriter == null)
                {
                    outputStreamWriter = new DataWriter(EventHandlerForSerialDevice.Current.Device.OutputStream);
                }

                // serial works as a "single channel" so we can only TX or RX,
                // meaning that access to the resource has to be protected with a semephore
                await semaphore.WaitAsync();

                try
                {
                    // write buffer to device
                    outputStreamWriter.WriteBytes(buffer);

                    // need to have a timeout to cancel the read task otherwise it may end up waiting forever for this to return
                    // because we have an external cancellation token and the above timeout cancellation token, need to combine both
                    Task <uint> storeAsyncTask = outputStreamWriter.StoreAsync().AsTask(cancellationToken.AddTimeout(waiTimeout));

                    bytesWritten = await storeAsyncTask;

                    if (bytesWritten > 0)
                    {
                        LastActivity = DateTime.Now;
                    }
                }
                catch (TaskCanceledException)
                {
                    // this is expected to happen, don't do anything with this
                }
                catch (Exception ex)
                {
                    Debug.WriteLine($"SendRawBufferAsync-Serial-Exception occurred: {ex.Message}\r\n {ex.StackTrace}");
                }
                finally
                {
                    semaphore.Release();
                    outputStreamWriter.DetachBuffer();
                }
            }
            else
            {
                // NotifyDeviceNotConnected
                Debug.WriteLine("NotifyDeviceNotConnected");
            }

            return(bytesWritten);
        }
Beispiel #10
0
        public static async Task <InitializationResult> HandleInitializationOfClient(
            Stream clientStream,
            byte[] presharedKey,
            Guid serverGuid,
            IAuthenticatedConnectionFactory authenticatedConnectionFactory,
            ICryptographicService otp,
            Action <Guid, AuthenticatedStream> onClientConnected,
            Action <Guid, X509Certificate> onClientRegistered,
            Func <Guid, X509Certificate> getClientPublicKey,
            CancellationToken token)
        {
            token = token.AddTimeout(DefaultTimeout);
            if (token.IsCancellationRequested)
            {
                return(new InitializationResult
                {
                    Successful = false,
                    Error = new InitializationError
                    {
                        ErrorType = InitializationErrorType.CancellationRequested,
                    }
                });
            }
            if (!await GetAndVerifyPresharedKey(clientStream, presharedKey, token))
            {
                return(new InitializationResult
                {
                    Successful = false,
                    Error = new InitializationError
                    {
                        ErrorType = InitializationErrorType.Protocol,
                        Message = "The received pre-shared key did not match the pre-shared key for this application",
                    },
                });
            }
            await clientStream.WriteSafelyAsync(serverGuid, token);

            var clientGuidResult = await clientStream.ReceiveGuidSafelyAsync(token);

            if (!clientGuidResult.Successful)
            {
                return(InitializationResult.From(clientGuidResult));
            }
            var clientGuid           = clientGuidResult.Result;
            var initiationModeResult = await clientStream.ReceiveInt32SafelyAsync(token);

            if (!initiationModeResult.Successful)
            {
                return(InitializationResult.From(initiationModeResult));
            }
            switch ((InitiationMode)initiationModeResult.Result)
            {
            case InitiationMode.Otp:
                var clientRegistrationResult =
                    await HandleClientRegistrationSafelyAsync(clientStream, serverGuid, authenticatedConnectionFactory, otp, token);

                if (clientRegistrationResult.Successful)
                {
                    var(certificate, stream) = clientRegistrationResult.Result;
                    onClientRegistered(clientGuid, certificate);
                    onClientConnected(clientGuid, stream);
                }
                else
                {
                    return(clientRegistrationResult);
                }
                return(new InitializationResult
                {
                    Successful = true,
                });

            case InitiationMode.Standard:
                var clientCertificate = getClientPublicKey(clientGuid);
                if (clientCertificate == null)
                {
                    return(InitializationResult.Failed);
                }
                //var sessionKey = SymmetricKey.GenerateNewKey(symmetric.KeyLength);

                var encryptedStreamResult = await EstablishEncryptedCommunication(true, serverGuid, authenticatedConnectionFactory, clientStream, token);

                if (!encryptedStreamResult.Successful)
                {
                    return(encryptedStreamResult);
                }
                onClientConnected(clientGuid, encryptedStreamResult.Result);
                return(new InitializationResult
                {
                    Successful = true,
                });

            case InitiationMode.None:
                return(new InitializationResult()
                {
                    Successful = false,
                    Error = new InitializationError()
                    {
                        ErrorType = InitializationErrorType.Protocol,
                        Message = "Client did not send a valid initiation mode",
                    },
                });

            default:
                throw new ProtocolException($"invalid initiation mode {initiationModeResult.Result}");
            }
        }
Beispiel #11
0
        /// <summary>
        /// Essential Rx method. Drives state machine by reading data and processing it. This works in
        /// conjunction with NotificationThreadWorker [Tx].
        /// </summary>
        internal async Task <IncomingMessage> ProcessAsync(CancellationToken cancellationToken)
        {
            int count;
            int bytesRead;

            try
            {
                switch (m_state)
                {
                case ReceiveState.Initialize:

                    if (cancellationToken.IsCancellationRequested)
                    {
                        // cancellation requested
                        return(null);
                    }

                    m_rawPos = 0;

                    m_base          = new MessageBase();
                    m_base.m_header = new Packet();

                    m_raw          = new MessageRaw();
                    m_raw.m_header = m_parent.CreateConverter().Serialize(m_base.m_header);

                    m_state = ReceiveState.WaitingForHeader;
                    DebuggerEventSource.Log.WireProtocolReceiveState(m_state);
                    goto case ReceiveState.WaitingForHeader;

                case ReceiveState.WaitingForHeader:
                    count = m_raw.m_header.Length - m_rawPos;

                    //Debug.WriteLine("WaitingForHeader");

                    // need to have a timeout to cancel the read task otherwise it may end up waiting forever for this to return
                    // because we have an external cancellation token and the above timeout cancellation token, need to combine both

                    bytesRead = await m_parent.ReadBufferAsync(m_raw.m_header, m_rawPos, count, request.waitRetryTimeout, cancellationToken.AddTimeout(request.waitRetryTimeout)).ConfigureAwait(false);

                    m_rawPos += bytesRead;

                    // sanity check
                    if (bytesRead != 32)
                    {
                        // doesn't look like a header, better restart
                        m_state = ReceiveState.Initialize;
                        goto case ReceiveState.Initialize;
                    }

                    while (m_rawPos > 0)
                    {
                        int flag_Debugger = ValidSignature(marker_Debugger);
                        int flag_Packet   = ValidSignature(marker_Packet);

                        if (flag_Debugger == 1 || flag_Packet == 1)
                        {
                            m_state = ReceiveState.ReadingHeader;
                            DebuggerEventSource.Log.WireProtocolReceiveState(m_state);
                            goto case ReceiveState.ReadingHeader;
                        }

                        if (flag_Debugger == 0 || flag_Packet == 0)
                        {
                            break;     // Partial match.
                        }

                        m_parent.App.SpuriousCharacters(m_raw.m_header, 0, 1);

                        Array.Copy(m_raw.m_header, 1, m_raw.m_header, 0, --m_rawPos);
                    }
                    break;

                case ReceiveState.ReadingHeader:
                    count = m_raw.m_header.Length - m_rawPos;

                    //Debug.WriteLine("ReadingHeader");

                    // need to have a timeout to cancel the read task otherwise it may end up waiting forever for this to return
                    // because we have an external cancellation token and the above timeout cancellation token, need to combine both

                    bytesRead = await m_parent.ReadBufferAsync(m_raw.m_header, m_rawPos, count, request.waitRetryTimeout, cancellationToken.AddTimeout(request.waitRetryTimeout)).ConfigureAwait(false);

                    m_rawPos += bytesRead;

                    if (bytesRead != count)
                    {
                        break;
                    }

                    m_state = ReceiveState.CompleteHeader;
                    DebuggerEventSource.Log.WireProtocolReceiveState(m_state);
                    goto case ReceiveState.CompleteHeader;
                //break;

                case ReceiveState.CompleteHeader:
                    try
                    {
                        //Debug.WriteLine("CompleteHeader");

                        m_parent.CreateConverter().Deserialize(m_base.m_header, m_raw.m_header);

                        if (VerifyHeader() == true)
                        {
                            //Debug.WriteLine("CompleteHeader, header OK");

                            bool fReply = (m_base.m_header.m_flags & Flags.c_Reply) != 0;

                            DebuggerEventSource.Log.WireProtocolRxHeader(m_base.m_header.m_crcHeader, m_base.m_header.m_crcData, m_base.m_header.m_cmd, m_base.m_header.m_flags, m_base.m_header.m_seq, m_base.m_header.m_seqReply, m_base.m_header.m_size);

                            if (m_base.m_header.m_size != 0)
                            {
                                m_raw.m_payload = new byte[m_base.m_header.m_size];
                                //reuse m_rawPos for position in header to read.
                                m_rawPos = 0;

                                m_state = ReceiveState.ReadingPayload;
                                DebuggerEventSource.Log.WireProtocolReceiveState(m_state);
                                goto case ReceiveState.ReadingPayload;
                            }
                            else
                            {
                                m_state = ReceiveState.CompletePayload;
                                DebuggerEventSource.Log.WireProtocolReceiveState(m_state);
                                goto case ReceiveState.CompletePayload;
                            }
                        }

                        //Debug.WriteLine("CompleteHeader, header not valid");
                    }
                    //catch (ThreadAbortException)
                    //{
                    //    throw;
                    //}
                    catch (Exception e)
                    {
                        Debug.WriteLine("Fault at payload deserialization:\n\n{0}", e.ToString());
                    }

                    m_state = ReceiveState.Initialize;
                    DebuggerEventSource.Log.WireProtocolReceiveState(m_state);

                    if ((m_base.m_header.m_flags & Flags.c_NonCritical) == 0)
                    {
                        // FIXME
                        // evaluate the purpose of this reply back to the NETMF device, the TinyCRL doesn't seem to have to handle this. In the end it looks like this does have any real purpose and will only be wasting CPU.
                        //await IncomingMessage.ReplyBadPacketAsync(m_parent, Flags.c_BadHeader).ConfigureAwait(false);
                        return(null);
                    }

                    break;

                case ReceiveState.ReadingPayload:
                    count = m_raw.m_payload.Length - m_rawPos;

                    //Debug.WriteLine("ReadingPayload");

                    // need to have a timeout to cancel the read task otherwise it may end up waiting forever for this to return
                    // because we have an external cancellation token and the above timeout cancellation token, need to combine both

                    bytesRead = await m_parent.ReadBufferAsync(m_raw.m_payload, m_rawPos, count, request.waitRetryTimeout, cancellationToken.AddTimeout(request.waitRetryTimeout)).ConfigureAwait(false);

                    m_rawPos += bytesRead;

                    if (bytesRead != count)
                    {
                        break;
                    }

                    m_state = ReceiveState.CompletePayload;
                    DebuggerEventSource.Log.WireProtocolReceiveState(m_state);
                    goto case ReceiveState.CompletePayload;

                case ReceiveState.CompletePayload:
                    //Debug.WriteLine("CompletePayload");

                    if (VerifyPayload() == true)
                    {
                        //Debug.WriteLine("CompletePayload payload OK");

                        try
                        {
                            bool fReply = (m_base.m_header.m_flags & Flags.c_Reply) != 0;

                            if ((m_base.m_header.m_flags & Flags.c_NACK) != 0)
                            {
                                m_raw.m_payload = null;
                            }

                            if (await ProcessMessage(this.GetCompleteMessage(), fReply).ConfigureAwait(false))
                            {
                                DebuggerEventSource.Log.WireProtocolReceiveState(m_state);

                                //Debug.WriteLine("*** leaving reassembler");

                                return(this.GetCompleteMessage());
                            }
                            else
                            {
                                // this is not the message we were waiting
                                // FIXME
                            }
                            //m_parent.App.ProcessMessage(this.GetCompleteMessage(), fReply);

                            //m_state = ReceiveState.Initialize;
                            //return;
                        }
                        //catch (ThreadAbortException)
                        //{
                        //    throw;
                        //}
                        catch (Exception e)
                        {
                            Debug.WriteLine("Fault at payload deserialization:\n\n{0}", e.ToString());
                        }
                    }
                    else
                    {
                        Debug.WriteLine("CompletePayload payload not valid");
                    }

                    m_state = ReceiveState.Initialize;
                    DebuggerEventSource.Log.WireProtocolReceiveState(m_state);

                    if ((m_base.m_header.m_flags & Flags.c_NonCritical) == 0)
                    {
                        // FIXME
                        // evaluate the purpose of this reply back to the NETMF device, the TinyCRL doesn't seem to have to handle this. In the end it looks like this does have any real purpose and will only be wasting CPU.
                        await IncomingMessage.ReplyBadPacketAsync(m_parent, Flags.c_BadPayload).ConfigureAwait(false);

                        return(null);
                    }

                    break;
                }
            }
            catch
            {
                m_state = ReceiveState.Initialize;
                DebuggerEventSource.Log.WireProtocolReceiveState(m_state);
                //Debug.WriteLine("*** leaving reassembler");
                throw;
            }

            //Debug.WriteLine("*** leaving reassembler");
            return(null);
        }