Exemplo n.º 1
0
        private void Run()
        {
            byte[] RxData = new byte[512]; // Rx buffer used for transferring data from the stream to the ring buffer
            NetworkStream Stream = _Client.GetStream();
            StompRingBuffer<byte> Buffer = new StompRingBuffer<byte>(RxBufferSize);

            // Run while the client is connected, polling for data rx'd and dispatching frames as necessary
            // Also handle heartbeats and heartbeat disconnect
            while (_Client.Connected)
            {
                // If we should be heartbeating, and we're connected...
                if (_Heartbeat > 0 && ConnectionVersion > 0.0f)
                {
                    // Sleep up to 15ms, or less if we need to heartbeat sooner
                    int SleepAmt = Math.Min(_HeartbeatTxIntervalTimeout, 15);

                    // If we expect to recieve heartbeats...
                    if (_HeartbeatRxInterval > 0)
                    {
                        // ...check that we've recieved data within the rx interval.  If not, disconnect.
                        _HeartbeatRxIntervalTimeout -= SleepAmt;
                        if (_HeartbeatRxIntervalTimeout < 0)
                        {
                            lock (_Client)
                            {
                                _Client.Close();
                            }
                            return;
                        }
                    }

                    // If we need to send heartbeats...
                    if (_HeartbeatTxInterval > 0)
                    {
                        // ... send one if it's been too long since our last transmission
                        _HeartbeatTxIntervalTimeout -= SleepAmt;
                        if (_HeartbeatTxIntervalTimeout < 0 && _HeartbeatTxInterval > 0)
                        {
                            _Client.GetStream().WriteByte((byte)'\n');
                            _HeartbeatTxIntervalTimeout = _HeartbeatTxInterval;
                        }
                    }

                    Thread.Sleep(SleepAmt);
                }
                else // Otherwise just do a standard sleep
                {
                    Thread.Sleep(15);
                }

                // Read in as much data from the stream as we can into the ring buffer
                while (_Client.Available > 0 && Buffer.AvailableWrite > 0)
                {
                    // We've received data, so reset the heartbeat rx timeout
                    _HeartbeatRxIntervalTimeout = (int)(_HeartbeatRxInterval * 1.5); // +50% forgiveness for heartbeat loss

                    // Now read in from the networkstream to the ring buffer
                    int AmtRead = Stream.Read(RxData, 0, Buffer.AvailableWrite);
                    Buffer.Write(RxData, AmtRead);
                }

                // Advance through any heartbeats rx'd or frame separators
                while (Buffer.Peek() == '\r' || Buffer.Peek() == '\n' || Buffer.Peek() == '\0')
                    Buffer.Read(1);

                // Now try to build + dispatch the packet
                if (!TryBuildPacket(Buffer) && Buffer.AvailableWrite == 0)
                    throw new InvalidOperationException("Ran out of receive ringbuffer space in STOMPClient");

            }
        }
Exemplo n.º 2
0
        /// <summary>
        ///     Tries to build a packet from the given ringbuffer
        /// </summary>
        /// <param name="Buffer">
        ///     The Ringbuffer to build a packet from
        /// </param>
        /// <returns>
        ///     Whether it was able to build a packet or not
        /// </returns>
        public bool TryBuildPacket(StompRingBuffer <byte> Buffer)
        {
            // See if we have rx'd a packet separator or a \0 in a binary frame body
            int PacketLength = Buffer.DistanceTo(0);

            // We have, so what did we find?
            if (PacketLength > 0)
            {
                // This is a really messy block of code.

                // The goal is that it tries to determine whether it has a full packet or needs to wait for more data
                // before building the packet and dispatching it

                byte[]   Data             = Buffer.Peek(PacketLength);
                string   Header           = Encoding.UTF8.GetString(Data);
                string[] HeaderCheck      = Header.Split('\n');
                int      ContentLength    = 0;
                bool     HasContentLength = false;

                // First, we look to see if our "packet" has a content-length header.  Since we scanned out to a null (\0) byte, we're guaranteed to at least have the headers
                // of whatever packet we're examining

                for (int i = 0; i < HeaderCheck.Length && HeaderCheck[i] != "" && HeaderCheck[i] != "\r"; i++)
                {
                    // We found a content-length header?  Flag it and store how large in bytes the content should be
                    if (HeaderCheck[i].StartsWith("content-length:"))
                    {
                        HasContentLength = true;
                        ContentLength    = int.Parse(HeaderCheck[i].Substring(15));
                    }
                }
                StompFrame Frame = null;

                if (HasContentLength)
                {
                    // We have a content-length header.  We need to find the start of the frame body, in bytes,
                    // and then make sure we have (ContentLength) bytes available after that

                    // Look for the end of the headers, either 1.0/1.1 or 1.2 (\r\n)-friendly
                    int EndOfHeaders = Header.IndexOf("\r\n\r\n") + 4;
                    if (EndOfHeaders == 3) // (-1) + 4
                    {
                        EndOfHeaders = Header.IndexOf("\n\n") + 2;
                    }

                    // Get the byte length of the header
                    int Offset = Encoding.UTF8.GetByteCount(Header.Substring(0, EndOfHeaders));

                    // Now see if we have that many bytes available in the ring buffer (realistically, we should except for obscene frame sizes)
                    if (Offset + ContentLength <= Buffer.AvailableRead)
                    {
                        // If we do, peek the exact packet length we want and assemble
                        Frame = StompFrame.Build(Buffer.Peek(Offset + ContentLength), _FrameTypeMapping);
                        Buffer.Seek(Offset + ContentLength);
                        DispatchFrame(Frame);

                        return(true);
                    }
                }
                else // No content-length.  We're guaranteed to be a text packet without any overshoot; no special treatment needed
                {
                    Frame = StompFrame.Build(Data, _FrameTypeMapping);
                    Buffer.Seek(PacketLength);
                    DispatchFrame(Frame);

                    return(true);
                }
            }

            return(false);
        }
Exemplo n.º 3
0
        /// <summary>
        ///     Tries to build a packet from the given ringbuffer
        /// </summary>
        /// <param name="Buffer">
        ///     The Ringbuffer to build a packet from
        /// </param>
        /// <returns>
        ///     Whether it was able to build a packet or not
        /// </returns>
        public bool TryBuildPacket(StompRingBuffer<byte> Buffer)
        {
            // See if we have rx'd a packet separator or a \0 in a binary frame body
            int PacketLength = Buffer.DistanceTo(0);

            // We have, so what did we find?
            if (PacketLength > 0)
            {
                // This is a really messy block of code.

                // The goal is that it tries to determine whether it has a full packet or needs to wait for more data
                // before building the packet and dispatching it

                byte[] Data = Buffer.Peek(PacketLength);
                string Header = Encoding.UTF8.GetString(Data);
                string[] HeaderCheck = Header.Split('\n');
                int ContentLength = 0;
                bool HasContentLength = false;

                // First, we look to see if our "packet" has a content-length header.  Since we scanned out to a null (\0) byte, we're guaranteed to at least have the headers
                // of whatever packet we're examining

                for (int i = 0; i < HeaderCheck.Length && HeaderCheck[i] != "" && HeaderCheck[i] != "\r"; i++)
                {
                    // We found a content-length header?  Flag it and store how large in bytes the content should be
                    if (HeaderCheck[i].StartsWith("content-length:"))
                    {
                        HasContentLength = true;
                        ContentLength = int.Parse(HeaderCheck[i].Substring(15));
                    }
                }
                StompFrame Frame = null;

                if (HasContentLength)
                {
                    // We have a content-length header.  We need to find the start of the frame body, in bytes,
                    // and then make sure we have (ContentLength) bytes available after that

                    // Look for the end of the headers, either 1.0/1.1 or 1.2 (\r\n)-friendly
                    int EndOfHeaders = Header.IndexOf("\r\n\r\n") + 4;
                    if (EndOfHeaders == 3) // (-1) + 4
                        EndOfHeaders = Header.IndexOf("\n\n") + 2;

                    // Get the byte length of the header
                    int Offset = Encoding.UTF8.GetByteCount(Header.Substring(0, EndOfHeaders));

                    // Now see if we have that many bytes available in the ring buffer (realistically, we should except for obscene frame sizes)
                    if (Offset + ContentLength <= Buffer.AvailableRead)
                    {
                        // If we do, peek the exact packet length we want and assemble
                        Frame = StompFrame.Build(Buffer.Peek(Offset + ContentLength), _FrameTypeMapping);
                        Buffer.Seek(Offset + ContentLength);
                        DispatchFrame(Frame);

                        return true;
                    }
                }
                else // No content-length.  We're guaranteed to be a text packet without any overshoot; no special treatment needed
                {
                    Frame = StompFrame.Build(Data, _FrameTypeMapping);
                    Buffer.Seek(PacketLength);
                    DispatchFrame(Frame);

                    return true;
                }
            }

            return false;
        }
Exemplo n.º 4
0
        private void Run()
        {
            byte[]                 RxData = new byte[512]; // Rx buffer used for transferring data from the stream to the ring buffer
            NetworkStream          Stream = _Client.GetStream();
            StompRingBuffer <byte> Buffer = new StompRingBuffer <byte>(RxBufferSize);

            // Run while the client is connected, polling for data rx'd and dispatching frames as necessary
            // Also handle heartbeats and heartbeat disconnect
            while (_Client.Connected)
            {
                // If we should be heartbeating, and we're connected...
                if (_Heartbeat > 0 && ConnectionVersion > 0.0f)
                {
                    // Sleep up to 15ms, or less if we need to heartbeat sooner
                    int SleepAmt = Math.Min(_HeartbeatTxIntervalTimeout, 15);

                    // If we expect to recieve heartbeats...
                    if (_HeartbeatRxInterval > 0)
                    {
                        // ...check that we've recieved data within the rx interval.  If not, disconnect.
                        _HeartbeatRxIntervalTimeout -= SleepAmt;
                        if (_HeartbeatRxIntervalTimeout < 0)
                        {
                            lock (_Client)
                            {
                                _Client.Close();
                            }
                            return;
                        }
                    }

                    // If we need to send heartbeats...
                    if (_HeartbeatTxInterval > 0)
                    {
                        // ... send one if it's been too long since our last transmission
                        _HeartbeatTxIntervalTimeout -= SleepAmt;
                        if (_HeartbeatTxIntervalTimeout < 0 && _HeartbeatTxInterval > 0)
                        {
                            _Client.GetStream().WriteByte((byte)'\n');
                            _HeartbeatTxIntervalTimeout = _HeartbeatTxInterval;
                        }
                    }

                    Thread.Sleep(SleepAmt);
                }
                else // Otherwise just do a standard sleep
                {
                    Thread.Sleep(15);
                }

                // Read in as much data from the stream as we can into the ring buffer
                while (_Client.Available > 0 && Buffer.AvailableWrite > 0)
                {
                    // We've received data, so reset the heartbeat rx timeout
                    _HeartbeatRxIntervalTimeout = (int)(_HeartbeatRxInterval * 1.5); // +50% forgiveness for heartbeat loss

                    // Now read in from the networkstream to the ring buffer
                    int AmtRead = Stream.Read(RxData, 0, Buffer.AvailableWrite);
                    Buffer.Write(RxData, AmtRead);
                }

                // Advance through any heartbeats rx'd or frame separators
                while (Buffer.Peek() == '\r' || Buffer.Peek() == '\n' || Buffer.Peek() == '\0')
                {
                    Buffer.Read(1);
                }

                // Now try to build + dispatch the packet
                if (!TryBuildPacket(Buffer) && Buffer.AvailableWrite == 0)
                {
                    throw new InvalidOperationException("Ran out of receive ringbuffer space in STOMPClient");
                }
            }
        }