예제 #1
0
        public StreamEngine(AsyncSocket handle, Options options, string endpoint)
        {
            this.m_handle         = handle;
            this.m_insize         = 0;
            this.m_ioEnabled      = false;
            this.m_sendingState   = SendState.Idle;
            this.m_receivingState = ReceiveState.Idle;
            this.m_outsize        = 0;
            this.m_session        = null;
            this.m_options        = options;
            this.m_plugged        = false;
            this.m_endpoint       = endpoint;
            this.m_socket         = null;
            this.m_encoder        = null;
            this.m_decoder        = null;
            this.m_actionsQueue   = new Queue <StateMachineAction>();

            // Set the socket buffer limits for the underlying socket.
            if (this.m_options.SendBuffer != 0)
            {
                this.m_handle.SendBufferSize = this.m_options.SendBuffer;
            }

            if (this.m_options.ReceiveBuffer != 0)
            {
                this.m_handle.ReceiveBufferSize = this.m_options.ReceiveBuffer;
            }
        }
예제 #2
0
        private void HandleHandshake(Action action, SocketError socketError, int bytesTransferred)
        {
            int bytesSent;
            int bytesReceived;

            switch (this.m_handshakeState)
            {
            case HandshakeState.Closed:
                switch (action)
                {
                case Action.Start:
                    // Send the 'length' and 'flags' fields of the identity message.
                    // The 'length' field is encoded in the long format.

                    this.m_greetingOutputBuffer[this.m_outsize++] = 0xff;
                    this.m_greetingOutputBuffer.PutLong(this.m_options.Endian, (long)this.m_options.IdentitySize + 1, 1);
                    this.m_outsize += 8;
                    this.m_greetingOutputBuffer[this.m_outsize++] = 0x7f;

                    this.m_outpos = new ByteArraySegment(this.m_greetingOutputBuffer);

                    this.m_handshakeState = HandshakeState.SendingGreeting;

                    this.BeginWrite(this.m_outpos, this.m_outsize);
                    break;

                default:
                    Debug.Assert(false);
                    break;
                }

                break;

            case HandshakeState.SendingGreeting:
                switch (action)
                {
                case Action.OutCompleted:
                    bytesSent = StreamEngine.EndWrite(socketError, bytesTransferred);

                    if (bytesSent == -1)
                    {
                        this.Error();
                    }
                    else
                    {
                        this.m_outpos.AdvanceOffset(bytesSent);
                        this.m_outsize -= bytesSent;

                        if (this.m_outsize > 0)
                        {
                            this.BeginWrite(this.m_outpos, this.m_outsize);
                        }
                        else
                        {
                            this.m_greetingBytesRead = 0;

                            ByteArraySegment greetingSegment = new ByteArraySegment(this.m_greeting, this.m_greetingBytesRead);

                            this.m_handshakeState = HandshakeState.ReceivingGreeting;

                            this.BeginRead(greetingSegment, StreamEngine.PreambleSize);
                        }
                    }

                    break;

                case Action.ActivateIn:
                case Action.ActivateOut:
                    // nothing to do
                    break;

                default:
                    Debug.Assert(false);
                    break;
                }

                break;

            case HandshakeState.ReceivingGreeting:
                switch (action)
                {
                case Action.InCompleted:
                    bytesReceived = StreamEngine.EndRead(socketError, bytesTransferred);

                    if (bytesReceived == -1)
                    {
                        this.Error();
                    }
                    else
                    {
                        this.m_greetingBytesRead += bytesReceived;

                        // check if it is an unversioned protocol
                        if (this.m_greeting[0] != 0xff || this.m_greetingBytesRead == 10 && (this.m_greeting[9] & 0x01) == 0)
                        {
                            this.m_encoder = new V1Encoder(Config.OutBatchSize, this.m_options.Endian);
                            this.m_encoder.SetMsgSource(this.m_session);

                            this.m_decoder = new V1Decoder(Config.InBatchSize, this.m_options.MaxMessageSize, this.m_options.Endian);
                            this.m_decoder.SetMsgSink(this.m_session);

                            // We have already sent the message header.
                            // Since there is no way to tell the encoder to
                            // skip the message header, we simply throw that
                            // header data away.
                            int              headerSize = this.m_options.IdentitySize + 1 >= 255 ? 10 : 2;
                            byte[]           tmp        = new byte[10];
                            ByteArraySegment bufferp    = new ByteArraySegment(tmp);

                            int bufferSize = headerSize;

                            this.m_encoder.GetData(ref bufferp, ref bufferSize);

                            Debug.Assert(bufferSize == headerSize);

                            // Make sure the decoder sees the data we have already received.
                            this.m_inpos  = new ByteArraySegment(this.m_greeting);
                            this.m_insize = this.m_greetingBytesRead;

                            // To allow for interoperability with peers that do not forward
                            // their subscriptions, we inject a phony subscription
                            // message into the incoming message stream. To put this
                            // message right after the identity message, we temporarily
                            // divert the message stream from session to ourselves.
                            if (this.m_options.SocketType == ZmqSocketType.Pub || this.m_options.SocketType == ZmqSocketType.Xpub)
                            {
                                this.m_decoder.SetMsgSink(this);
                            }

                            // handshake is done
                            this.Activate();
                        }
                        else if (this.m_greetingBytesRead < 10)
                        {
                            ByteArraySegment greetingSegment = new ByteArraySegment(this.m_greeting, this.m_greetingBytesRead);
                            this.BeginRead(greetingSegment, StreamEngine.PreambleSize - this.m_greetingBytesRead);
                        }
                        else
                        {
                            // The peer is using versioned protocol.
                            // Send the rest of the greeting.
                            this.m_outpos[this.m_outsize++] = 1;         // Protocol version
                            this.m_outpos[this.m_outsize++] = (byte)this.m_options.SocketType;

                            this.m_handshakeState = HandshakeState.SendingRestOfGreeting;

                            this.BeginWrite(this.m_outpos, this.m_outsize);
                        }
                    }

                    break;

                case Action.ActivateIn:
                case Action.ActivateOut:
                    // nothing to do
                    break;

                default:
                    Debug.Assert(false);
                    break;
                }

                break;

            case HandshakeState.SendingRestOfGreeting:
                switch (action)
                {
                case Action.OutCompleted:
                    bytesSent = StreamEngine.EndWrite(socketError, bytesTransferred);

                    if (bytesSent == -1)
                    {
                        this.Error();
                    }
                    else
                    {
                        this.m_outpos.AdvanceOffset(bytesSent);
                        this.m_outsize -= bytesSent;

                        if (this.m_outsize > 0)
                        {
                            this.BeginWrite(this.m_outpos, this.m_outsize);
                        }
                        else
                        {
                            ByteArraySegment greetingSegment = new ByteArraySegment(this.m_greeting, this.m_greetingBytesRead);

                            this.m_handshakeState = HandshakeState.ReceivingRestOfGreeting;
                            this.BeginRead(greetingSegment, StreamEngine.GreetingSize - this.m_greetingBytesRead);
                        }
                    }

                    break;

                case Action.ActivateIn:
                case Action.ActivateOut:
                    // nothing to do
                    break;

                default:
                    Debug.Assert(false);
                    break;
                }

                break;

            case HandshakeState.ReceivingRestOfGreeting:
                switch (action)
                {
                case Action.InCompleted:
                    bytesReceived = StreamEngine.EndRead(socketError, bytesTransferred);

                    if (bytesReceived == -1)
                    {
                        this.Error();
                    }
                    else
                    {
                        this.m_greetingBytesRead += bytesReceived;

                        if (this.m_greetingBytesRead < StreamEngine.GreetingSize)
                        {
                            ByteArraySegment greetingSegment = new ByteArraySegment(this.m_greeting, this.m_greetingBytesRead);
                            this.BeginRead(greetingSegment, StreamEngine.GreetingSize - this.m_greetingBytesRead);
                        }
                        else
                        {
                            if (this.m_greeting[StreamEngine.VersionPos] == 0)
                            {
                                // ZMTP/1.0 framing.
                                this.m_encoder = new V1Encoder(Config.OutBatchSize, this.m_options.Endian);
                                this.m_encoder.SetMsgSource(this.m_session);

                                this.m_decoder = new V1Decoder(Config.InBatchSize, this.m_options.MaxMessageSize, this.m_options.Endian);
                                this.m_decoder.SetMsgSink(this.m_session);
                            }
                            else
                            {
                                // v1 framing protocol.
                                this.m_encoder = new V2Encoder(Config.OutBatchSize, this.m_session, this.m_options.Endian);
                                this.m_decoder = new V2Decoder(Config.InBatchSize, this.m_options.MaxMessageSize, this.m_session, this.m_options.Endian);
                            }

                            // handshake is done
                            this.Activate();
                        }
                    }

                    break;

                case Action.ActivateIn:
                case Action.ActivateOut:
                    // nothing to do
                    break;

                default:
                    Debug.Assert(false);
                    break;
                }

                break;

            default:
                Debug.Assert(false);
                break;
            }
        }
예제 #3
0
        private void Handle(Action action, SocketError socketError, int bytesTransferred)
        {
            switch (this.m_state)
            {
            case State.Closed:
                switch (action)
                {
                case Action.Start:
                    if (this.m_options.RawSocket)
                    {
                        this.m_encoder = new RawEncoder(Config.OutBatchSize, this.m_session, this.m_options.Endian);
                        this.m_decoder = new RawDecoder(Config.InBatchSize, this.m_options.MaxMessageSize, this.m_session, this.m_options.Endian);

                        this.Activate();
                    }
                    else
                    {
                        this.m_state          = State.Handshaking;
                        this.m_handshakeState = HandshakeState.Closed;
                        this.HandleHandshake(action, socketError, bytesTransferred);
                    }

                    break;
                }

                break;

            case State.Handshaking:
                this.HandleHandshake(action, socketError, bytesTransferred);
                break;

            case State.Active:
                switch (action)
                {
                case Action.InCompleted:
                    this.m_insize = StreamEngine.EndRead(socketError, bytesTransferred);

                    this.ProcessInput();
                    break;

                case Action.ActivateIn:

                    // if we stuck let's continue, other than that nothing to do
                    if (this.m_receivingState == ReceiveState.Stuck)
                    {
                        this.m_receivingState = ReceiveState.Active;
                        this.ProcessInput();
                    }

                    break;

                case Action.OutCompleted:
                    int bytesSent = StreamEngine.EndWrite(socketError, bytesTransferred);

                    // 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 incoming messages.
                    if (bytesSent == -1)
                    {
                        this.m_sendingState = SendState.Error;
                    }
                    else
                    {
                        this.m_outpos.AdvanceOffset(bytesSent);
                        this.m_outsize -= bytesSent;

                        this.BeginSending();
                    }

                    break;

                case Action.ActivateOut:
                    // if we idle we start sending, other than do nothing
                    if (this.m_sendingState == SendState.Idle)
                    {
                        this.m_sendingState = SendState.Active;
                        this.BeginSending();
                    }

                    break;

                default:
                    Debug.Assert(false);
                    break;
                }

                break;

            case State.Stalled:
                switch (action)
                {
                case Action.ActivateIn:
                    // There was an input error but the engine could not
                    // be terminated (due to the stalled decoder).
                    // Flush the pending message and terminate the engine now.
                    this.m_decoder.ProcessBuffer(this.m_inpos, 0);
                    Debug.Assert(!this.m_decoder.Stalled());
                    this.m_session.Flush();
                    this.Error();
                    break;

                case Action.ActivateOut:
                    break;
                }

                break;
            }
        }