コード例 #1
0
        public void OutEvent()
        {
            //  If write buffer is empty, try to read new data from the encoder.
            if (m_outsize == 0)
            {
                m_outpos = null;
                m_encoder.GetData(ref m_outpos, ref m_outsize);

                //  If there is no data to send, stop polling for output.
                if (m_outsize == 0)
                {
                    m_ioObject.ResetPollout(m_handle);

                    return;
                }
            }

            //  If there are any data to write in write buffer, write as much as
            //  possible to the socket. Note that amount of data to write can be
            //  arbitratily large. However, we assume that underlying TCP layer has
            //  limited transmission buffer and thus the actual number of bytes
            //  written should be reasonably modest.
            int nbytes = Write(m_outpos, m_outsize);

            //  IO error has occurred. We stop waiting for output events.
            //  The engine is not terminated until we detect input error;
            //  this is necessary to prevent losing incomming messages.
            if (nbytes == -1)
            {
                m_ioObject.ResetPollout(m_handle);
                return;
            }

            m_outpos.AdvanceOffset(nbytes);
            m_outsize -= nbytes;

            //  If we are still handshaking and there are no data
            //  to send, stop polling for output.
            if (m_handshaking)
            {
                if (m_outsize == 0)
                {
                    m_ioObject.ResetPollout(m_handle);
                }
            }
        }
コード例 #2
0
        public void InEvent()
        {
            //  If still handshaking, receive and process the greeting message.
            if (m_handshaking)
            {
                if (!Handshake())
                {
                    return;
                }
            }

            Debug.Assert(m_decoder != null);
            bool disconnection = false;
            int  processed;

            //  If there's no data to process in the buffer...
            if (m_insize == 0)
            {
                //  Retrieve the buffer and read as much data as possible.
                //  Note that buffer can be arbitrarily large. However, we assume
                //  the underlying TCP layer has fixed buffer size and thus the
                //  number of bytes read will be always limited.
                m_decoder.GetBuffer(ref m_inpos, ref m_insize);
                m_insize = Read(m_inpos, m_insize);

                //  Check whether the peer has closed the connection.
                if (m_insize == -1)
                {
                    m_insize      = 0;
                    disconnection = true;
                }
            }

            if (m_options.RawSocket)
            {
                if (m_insize == 0 || !m_decoder.MessageReadySize(m_insize))
                {
                    processed = 0;
                }
                else
                {
                    processed = m_decoder.ProcessBuffer(m_inpos, m_insize);
                }
            }
            else
            {
                //  Push the data to the decoder.
                processed = m_decoder.ProcessBuffer(m_inpos, m_insize);
            }

            if (processed == -1)
            {
                disconnection = true;
            }
            else
            {
                //  Stop polling for input if we got stuck.
                if (processed < m_insize)
                {
                    m_ioObject.ResetPollin(m_handle);
                }

                m_inpos.AdvanceOffset(processed);
                m_insize -= processed;
            }

            //  Flush all messages the decoder may have produced.
            m_session.Flush();

            //  An input error has occurred. If the last decoded message
            //  has already been accepted, we terminate the engine immediately.
            //  Otherwise, we stop waiting for socket events and postpone
            //  the termination until after the message is accepted.
            if (disconnection)
            {
                if (m_decoder.Stalled())
                {
                    m_ioObject.RmFd(m_handle);
                    m_inputError = true;
                }
                else
                {
                    Error();
                }
            }
        }
コード例 #3
0
        public void GetData(ref ByteArraySegment data, ref int size, ref int offset)
        {
            ByteArraySegment buffer = data ?? new ByteArraySegment(m_buf);
            int bufferSize          = data == null ? m_buffersize : size;

            int pos = 0;

            while (pos < bufferSize)
            {
                //  If there are no more data to return, run the state machine.
                //  If there are still no data, return what we already have
                //  in the buffer.
                if (m_toWrite == 0)
                {
                    //  If we are to encode the beginning of a new message,
                    //  adjust the message offset.

                    if (m_beginning)
                    {
                        if (offset == -1)
                        {
                            offset = pos;
                        }
                    }

                    if (!Next())
                    {
                        break;
                    }
                }

                //  If there are no data in the buffer yet and we are able to
                //  fill whole buffer in a single go, let's use zero-copy.
                //  There's no disadvantage to it as we cannot stuck multiple
                //  messages into the buffer anyway. Note that subsequent
                //  write(s) are non-blocking, thus each single write writes
                //  at most SO_SNDBUF bytes at once not depending on how large
                //  is the chunk returned from here.
                //  As a consequence, large messages being sent won't block
                //  other engines running in the same I/O thread for excessive
                //  amounts of time.
                if (pos == 0 && data == null && m_toWrite >= bufferSize)
                {
                    data = m_writePos;
                    size = m_toWrite;

                    m_writePos = null;
                    m_toWrite  = 0;
                    return;
                }

                //  Copy data to the buffer. If the buffer is full, return.
                int toCopy = Math.Min(m_toWrite, bufferSize - pos);

                if (toCopy != 0)
                {
                    m_writePos.CopyTo(0, buffer, pos, toCopy);
                    pos += toCopy;
                    m_writePos.AdvanceOffset(toCopy);
                    m_toWrite -= toCopy;
                }
            }

            data = buffer;
            size = pos;
        }
コード例 #4
0
        //  Processes the data in the buffer previously allocated using
        //  get_buffer function. size_ argument specifies nemuber of bytes
        //  actually filled into the buffer. Function returns number of
        //  bytes actually processed.
        public int ProcessBuffer(ByteArraySegment data, int size)
        {
            //  Check if we had an error in previous attempt.
            if (State < 0)
            {
                return(-1);
            }

            //  In case of zero-copy simply adjust the pointers, no copying
            //  is required. Also, run the state machine in case all the data
            //  were processed.
            if (data.Equals(m_readPos))
            {
                m_readPos.AdvanceOffset(size);
                m_toRead -= size;

                while (m_toRead == 0)
                {
                    if (!Next())
                    {
                        if (State < 0)
                        {
                            return(-1);
                        }
                        return(size);
                    }
                }
                return(size);
            }

            int pos = 0;

            while (true)
            {
                //  Try to get more space in the message to fill in.
                //  If none is available, return.
                while (m_toRead == 0)
                {
                    if (!Next())
                    {
                        if (State < 0)
                        {
                            return(-1);
                        }

                        return(pos);
                    }
                }

                //  If there are no more data in the buffer, return.
                if (pos == size)
                {
                    return(pos);
                }

                //  Copy the data from buffer to the message.
                int toCopy = Math.Min(m_toRead, size - pos);
                data.CopyTo(pos, m_readPos, 0, toCopy);
                m_readPos.AdvanceOffset(toCopy);
                pos      += toCopy;
                m_toRead -= toCopy;
            }
        }
コード例 #5
0
        public void InEvent()
        {
            if (m_pendingBytes > 0)
            {
                return;
            }

            //  Get new batch of data.
            //  Note the workaround made not to break strict-aliasing rules.
            data.Reset();

            int received = 0;

            try
            {
                received = m_handle.Receive((byte[])data);
            }
            catch (SocketException ex)
            {
                if (ex.SocketErrorCode == SocketError.WouldBlock)
                {
                    return;
                    //break;
                }
                else
                {
                    m_joined = false;
                    Error();
                    return;
                }
            }

            //  No data to process. This may happen if the packet received is
            //  neither ODATA nor ODATA.
            if (received == 0)
            {
                return;
            }

            //  Read the offset of the fist message in the current packet.
            Debug.Assert(received >= sizeof(ushort));
            ushort offset = data.GetUnsignedShort(m_options.Endian, 0);

            data.AdvanceOffset(sizeof(ushort));
            received -= sizeof(ushort);

            //  Join the stream if needed.
            if (!m_joined)
            {
                //  There is no beginning of the message in current packet.
                //  Ignore the data.
                if (offset == 0xffff)
                {
                    return;
                }

                Debug.Assert(offset <= received);
                Debug.Assert(m_decoder == null);

                //  We have to move data to the begining of the first message.
                data.AdvanceOffset(offset);
                received -= offset;

                //  Mark the stream as joined.
                m_joined = true;

                //  Create and connect decoder for the peer.
                m_decoder = new Decoder(0, m_options.Maxmsgsize, m_options.Endian);
                m_decoder.SetMsgSink(m_session);
            }

            //  Push all the data to the decoder.
            int processed = m_decoder.ProcessBuffer(data, received);

            if (processed < received)
            {
                //  Save some state so we can resume the decoding process later.
                m_pendingBytes = received - processed;
                m_pendingData  = new ByteArraySegment(data, processed);

                //  Stop polling.
                m_ioObject.ResetPollin(m_handle);

                return;
            }

            m_session.Flush();
        }