private void Unplug()
        {
            Debug.Assert(m_plugged);
            m_plugged = false;

            // remove handle from proactor.
            if (m_ioEnabled)
            {
                m_ioObject.RemoveSocket(m_handle);
                m_ioEnabled = false;
            }

            // Disconnect from I/O threads poller object.
            m_ioObject.Unplug();

            m_state = State.Closed;

            // Disconnect from session object.
            if (m_encoder != null)
            {
                m_encoder.SetMsgSource(null);
            }
            if (m_decoder != null)
            {
                m_decoder.SetMsgSink(null);
            }
            m_session = null;
        }
Example #2
0
        public bool PushMsg(ref Msg msg)
        {
            Debug.Assert(m_options.SocketType == ZmqSocketType.Pub || m_options.SocketType == ZmqSocketType.Xpub);

            // The first message is identity.
            // Let the session process it.

            m_session.PushMsg(ref msg);

            // Inject the subscription message so that the ZMQ 2.x peer
            // receives our messages.
            msg.InitPool(1);
            msg.Put((byte)1);

            bool isMessagePushed = m_session.PushMsg(ref msg);

            m_session.Flush();

            // Once we have injected the subscription message, we can
            // Divert the message flow back to the session.
            Debug.Assert(m_decoder != null);
            m_decoder.SetMsgSink(m_session);

            return(isMessagePushed);
        }
        private void HandleHandshake(Action action, SocketError socketError, int bytesTransferred)
        {
            int bytesSent;
            int bytesReceived;

            switch (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.

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

                    m_outpos = new ByteArraySegment(m_greetingOutputBuffer);

                    m_handshakeState = HandshakeState.SendingGreeting;

                    BeginWrite(m_outpos, m_outsize);
                    break;

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

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

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

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

                            var greetingSegment = new ByteArraySegment(m_greeting, m_greetingBytesRead);

                            m_handshakeState = HandshakeState.ReceivingGreeting;

                            BeginRead(greetingSegment, 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 = EndRead(socketError, bytesTransferred);

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

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

                            m_decoder = new V1Decoder(Config.InBatchSize, m_options.MaxMessageSize, m_options.Endian);
                            m_decoder.SetMsgSink(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 = m_options.IdentitySize + 1 >= 255 ? 10 : 2;
                            var tmp        = new byte[10];
                            var bufferp    = new ByteArraySegment(tmp);

                            int bufferSize = headerSize;

                            m_encoder.GetData(ref bufferp, ref bufferSize);

                            Debug.Assert(bufferSize == headerSize);

                            // Make sure the decoder sees the data we have already received.
                            m_inpos  = new ByteArraySegment(m_greeting);
                            m_insize = 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 (m_options.SocketType == ZmqSocketType.Pub || m_options.SocketType == ZmqSocketType.Xpub)
                            {
                                m_decoder.SetMsgSink(this);
                            }

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

                            m_handshakeState = HandshakeState.SendingRestOfGreeting;

                            BeginWrite(m_outpos, 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 = EndWrite(socketError, bytesTransferred);

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

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

                            m_handshakeState = HandshakeState.ReceivingRestOfGreeting;
                            BeginRead(greetingSegment, GreetingSize - 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 = EndRead(socketError, bytesTransferred);

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

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

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

                            // handshake is done
                            Activate();
                        }
                    }
                    break;

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

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

            default:
                Debug.Assert(false);
                break;
            }
        }
Example #4
0
        private void HandleHandshake(Action action, SocketError socketError, int bytesTransferred)
        {
            int bytesSent;
            int bytesReceived;

            switch (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.

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

                            m_outpos = new ByteArraySegment(m_greetingOutputBuffer);

                            m_handshakeState = HandshakeState.SendingGreeting;

                            BeginWrite(m_outpos, m_outsize);
                            break;
                        default:
                            Debug.Assert(false);
                            break;
                    }
                    break;
                case HandshakeState.SendingGreeting:
                    switch (action)
                    {
                        case Action.OutCompleted:
                            bytesSent = EndWrite(socketError, bytesTransferred);

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

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

                                    var greetingSegment = new ByteArraySegment(m_greeting, m_greetingBytesRead);

                                    m_handshakeState = HandshakeState.ReceivingGreeting;

                                    BeginRead(greetingSegment, 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 = EndRead(socketError, bytesTransferred);

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

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

                                    m_decoder = new V1Decoder(Config.InBatchSize, m_options.MaxMessageSize, m_options.Endian);
                                    m_decoder.SetMsgSink(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 = m_options.IdentitySize + 1 >= 255 ? 10 : 2;
                                    var tmp = new byte[10];
                                    var bufferp = new ByteArraySegment(tmp);

                                    int bufferSize = headerSize;

                                    m_encoder.GetData(ref bufferp, ref bufferSize);

                                    Debug.Assert(bufferSize == headerSize);

                                    // Make sure the decoder sees the data we have already received.
                                    m_inpos = new ByteArraySegment(m_greeting);
                                    m_insize = 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 (m_options.SocketType == ZmqSocketType.Pub || m_options.SocketType == ZmqSocketType.Xpub)
                                        m_decoder.SetMsgSink(this);

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

                                    m_handshakeState = HandshakeState.SendingRestOfGreeting;

                                    BeginWrite(m_outpos, 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 = EndWrite(socketError, bytesTransferred);

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

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

                                    m_handshakeState = HandshakeState.ReceivingRestOfGreeting;
                                    BeginRead(greetingSegment, GreetingSize - 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 = EndRead(socketError, bytesTransferred);

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

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

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

                                    // handshake is done
                                    Activate();
                                }
                            }
                            break;
                        case Action.ActivateIn:
                        case Action.ActivateOut:
                            // nothing to do
                            break;
                        default:
                            Debug.Assert(false);
                            break;
                    }
                    break;
                default:
                    Debug.Assert(false);
                    break;
            }
        }