Beispiel #1
0
void zmq::stream_engine_t::plug (io_thread_t *io_thread_,
    session_base_t *session_)
{
    zmq_assert (!plugged);
    plugged = true;

    //  Connect to session object.
    zmq_assert (!session);
    zmq_assert (session_);
    encoder.set_session (session_);
    decoder.set_session (session_);
    session = session_;

    //  Connect to I/O threads poller object.
    io_object_t::plug (io_thread_);
    handle = add_fd (s);
    set_pollin (handle);
    set_pollout (handle);
    //  Flush all the data that may have been already received downstream.
    in_event ();
}
Beispiel #2
0
void zmq::zmq_engine_t::plug (io_thread_t *io_thread_, i_inout *inout_)
{
    zmq_assert (!plugged);
    plugged = true;
    ephemeral_inout = NULL;

    //  Connect to session/init object.
    zmq_assert (!inout);
    zmq_assert (inout_);
    encoder.set_inout (inout_);
    decoder.set_inout (inout_);
    inout = inout_;

    //  Connect to I/O threads poller object.
    io_object_t::plug (io_thread_);
    handle = add_fd (tcp_socket.get_fd ());
    set_pollin (handle);
    set_pollout (handle);

    //  Flush all the data that may have been already received downstream.
    in_event ();
}
Beispiel #3
0
void xs::stream_engine_t::plug (io_thread_t *io_thread_,
    session_base_t *session_)
{
    xs_assert (!plugged);
    plugged = true;
    leftover_session = NULL;

    //  Connect to session object.
    xs_assert (!session);
    xs_assert (session_);
    encoder.set_session (session_);
    decoder.set_session (session_);
    session = session_;

    //  Connect to the io_thread object.
    io_object_t::plug (io_thread_);
    handle = add_fd (s);
    set_pollin (handle);
    set_pollout (handle);

    //  Flush all the data that may have been already received downstream.
    in_event (s);
}
Beispiel #4
0
bool zmq::stream_engine_t::handshake ()
{
    zmq_assert (handshaking);
    zmq_assert (greeting_bytes_read < greeting_size);
    //  Receive the greeting.
    while (greeting_bytes_read < greeting_size) {
        const int n = tcp_read (s, greeting_recv + greeting_bytes_read,
                                greeting_size - greeting_bytes_read);
        if (n == 0) {
            error (connection_error);
            return false;
        }
        if (n == -1) {
            if (errno != EAGAIN)
                error (connection_error);
            return false;
        }

        greeting_bytes_read += n;

        //  We have received at least one byte from the peer.
        //  If the first byte is not 0xff, we know that the
        //  peer is using unversioned protocol.
        if (greeting_recv [0] != 0xff)
            break;

        if (greeting_bytes_read < signature_size)
            continue;

        //  Inspect the right-most bit of the 10th byte (which coincides
        //  with the 'flags' field if a regular message was sent).
        //  Zero indicates this is a header of identity message
        //  (i.e. the peer is using the unversioned protocol).
        if (!(greeting_recv [9] & 0x01))
            break;

        //  The peer is using versioned protocol.
        //  Send the major version number.
        if (outpos + outsize == greeting_send + signature_size) {
            if (outsize == 0)
                set_pollout (handle);
            outpos [outsize++] = 3;     //  Major version number
        }

        if (greeting_bytes_read > signature_size) {
            if (outpos + outsize == greeting_send + signature_size + 1) {
                if (outsize == 0)
                    set_pollout (handle);

                //  Use ZMTP/2.0 to talk to older peers.
                if (greeting_recv [10] == ZMTP_1_0
                ||  greeting_recv [10] == ZMTP_2_0)
                    outpos [outsize++] = options.type;
                else {
                    outpos [outsize++] = 0; //  Minor version number
                    memset (outpos + outsize, 0, 20);

                    zmq_assert (options.mechanism == ZMQ_NULL
                            ||  options.mechanism == ZMQ_PLAIN
                            ||  options.mechanism == ZMQ_CURVE
                            ||  options.mechanism == ZMQ_GSSAPI);

                    if (options.mechanism == ZMQ_NULL)
                        memcpy (outpos + outsize, "NULL", 4);
                    else
                    if (options.mechanism == ZMQ_PLAIN)
                        memcpy (outpos + outsize, "PLAIN", 5);
                    else
                    if (options.mechanism == ZMQ_GSSAPI)
                        memcpy (outpos + outsize, "GSSAPI", 6);
                    else
                    if (options.mechanism == ZMQ_CURVE)
                        memcpy (outpos + outsize, "CURVE", 5);
                    outsize += 20;
                    memset (outpos + outsize, 0, 32);
                    outsize += 32;
                    greeting_size = v3_greeting_size;
                }
            }
        }
    }

    //  Position of the revision field in the greeting.
    const size_t revision_pos = 10;

    //  Is the peer using ZMTP/1.0 with no revision number?
    //  If so, we send and receive rest of identity message
    if (greeting_recv [0] != 0xff || !(greeting_recv [9] & 0x01)) {
        if (session->zap_enabled ()) {
           // reject ZMTP 1.0 connections if ZAP is enabled
           error (protocol_error);
           return false;
        }

        encoder = new (std::nothrow) v1_encoder_t (out_batch_size);
        alloc_assert (encoder);

        decoder = new (std::nothrow) v1_decoder_t (in_batch_size, options.maxmsgsize);
        alloc_assert (decoder);

        //  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.
        const size_t header_size = options.identity_size + 1 >= 255 ? 10 : 2;
        unsigned char tmp [10], *bufferp = tmp;

        //  Prepare the identity message and load it into encoder.
        //  Then consume bytes we have already sent to the peer.
        const int rc = tx_msg.init_size (options.identity_size);
        zmq_assert (rc == 0);
        memcpy (tx_msg.data (), options.identity, options.identity_size);
        encoder->load_msg (&tx_msg);
        size_t buffer_size = encoder->encode (&bufferp, header_size);
        zmq_assert (buffer_size == header_size);

        //  Make sure the decoder sees the data we have already received.
        inpos = greeting_recv;
        insize = greeting_bytes_read;

        //  To allow for interoperability with peers that do not forward
        //  their subscriptions, we inject a phantom subscription message
        //  message into the incoming message stream.
        if (options.type == ZMQ_PUB || options.type == ZMQ_XPUB)
            subscription_required = true;

        //  We are sending our identity now and the next message
        //  will come from the socket.
        next_msg = &stream_engine_t::pull_msg_from_session;

        //  We are expecting identity message.
        process_msg = &stream_engine_t::process_identity_msg;
    }
    else
    if (greeting_recv [revision_pos] == ZMTP_1_0) {
        if (session->zap_enabled ()) {
           // reject ZMTP 1.0 connections if ZAP is enabled
           error (protocol_error);
           return false;
        }

        encoder = new (std::nothrow) v1_encoder_t (
            out_batch_size);
        alloc_assert (encoder);

        decoder = new (std::nothrow) v1_decoder_t (
            in_batch_size, options.maxmsgsize);
        alloc_assert (decoder);
    }
    else
    if (greeting_recv [revision_pos] == ZMTP_2_0) {
        if (session->zap_enabled ()) {
           // reject ZMTP 2.0 connections if ZAP is enabled
           error (protocol_error);
           return false;
        }

        encoder = new (std::nothrow) v2_encoder_t (out_batch_size);
        alloc_assert (encoder);

        decoder = new (std::nothrow) v2_decoder_t (
            in_batch_size, options.maxmsgsize);
        alloc_assert (decoder);
    }
    else {
        encoder = new (std::nothrow) v2_encoder_t (out_batch_size);
        alloc_assert (encoder);

        decoder = new (std::nothrow) v2_decoder_t (
            in_batch_size, options.maxmsgsize);
        alloc_assert (decoder);

        if (options.mechanism == ZMQ_NULL
        &&  memcmp (greeting_recv + 12, "NULL\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) == 0) {
            mechanism = new (std::nothrow)
                null_mechanism_t (session, peer_address, options);
            alloc_assert (mechanism);
        }
        else
        if (options.mechanism == ZMQ_PLAIN
        &&  memcmp (greeting_recv + 12, "PLAIN\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) == 0) {
            if (options.as_server)
                mechanism = new (std::nothrow)
                    plain_server_t (session, peer_address, options);
            else
                mechanism = new (std::nothrow)
                    plain_client_t (options);
            alloc_assert (mechanism);
        }
#ifdef HAVE_LIBSODIUM
        else
        if (options.mechanism == ZMQ_CURVE
        &&  memcmp (greeting_recv + 12, "CURVE\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) == 0) {
            if (options.as_server)
                mechanism = new (std::nothrow)
                    curve_server_t (session, peer_address, options);
            else
                mechanism = new (std::nothrow) curve_client_t (options);
            alloc_assert (mechanism);
        }
#endif
#ifdef HAVE_LIBGSSAPI_KRB5
        else
        if (options.mechanism == ZMQ_GSSAPI
        &&  memcmp (greeting_recv + 12, "GSSAPI\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) == 0) {
            if (options.as_server)
                mechanism = new (std::nothrow)
                    gssapi_server_t (session, peer_address, options);
            else
                mechanism = new (std::nothrow) gssapi_client_t (options);
            alloc_assert (mechanism);
        }
#endif
        else {
            //  Temporary support for security debugging
            char mechanism [21];
            memcpy (mechanism, greeting_recv + 12, 20);
            mechanism [20] = 0;
            printf ("LIBZMQ I: security failure, self=%s peer=%s\n",
                options.mechanism == ZMQ_NULL? "NULL":
                options.mechanism == ZMQ_PLAIN? "PLAIN":
                options.mechanism == ZMQ_CURVE? "CURVE":
                options.mechanism == ZMQ_GSSAPI? "GSSAPI":
                "OTHER",
                mechanism);

            error (protocol_error);
            return false;
        }
        next_msg = &stream_engine_t::next_handshake_command;
        process_msg = &stream_engine_t::process_handshake_command;
    }

    // Start polling for output if necessary.
    if (outsize == 0)
        set_pollout (handle);

    //  Handshaking was successful.
    //  Switch into the normal message flow.
    handshaking = false;

    if (has_handshake_timer) {
        cancel_timer (handshake_timer_id);
        has_handshake_timer = false;
    }

    return true;
}
Beispiel #5
0
void zmq::stream_engine_t::plug (io_thread_t *io_thread_,
    session_base_t *session_)
{
    zmq_assert (!plugged);
    plugged = true;

    //  Connect to session object.
    zmq_assert (!session);
    zmq_assert (session_);
    session = session_;
    socket = session-> get_socket ();

    //  Connect to I/O threads poller object.
    io_object_t::plug (io_thread_);
    handle = add_fd (s);
    io_error = false;

    if (options.raw_socket) {
        // no handshaking for raw sock, instantiate raw encoder and decoders
        encoder = new (std::nothrow) raw_encoder_t (out_batch_size);
        alloc_assert (encoder);

        decoder = new (std::nothrow) raw_decoder_t (in_batch_size);
        alloc_assert (decoder);

        // disable handshaking for raw socket
        handshaking = false;

        next_msg = &stream_engine_t::pull_msg_from_session;
        process_msg = &stream_engine_t::push_raw_msg_to_session;

        properties_t properties;
        if (init_properties(properties)) {
            //  Compile metadata.
            zmq_assert (metadata == NULL);
            metadata = new (std::nothrow) metadata_t (properties);
        }

        if (options.raw_notify) {
            //  For raw sockets, send an initial 0-length message to the
            // application so that it knows a peer has connected.
            msg_t connector;
            connector.init();
            push_raw_msg_to_session (&connector);
            connector.close();
            session->flush ();
        }
    }
    else {
        // start optional timer, to prevent handshake hanging on no input
        set_handshake_timer ();

        //  Send the 'length' and 'flags' fields of the identity message.
        //  The 'length' field is encoded in the long format.
        outpos = greeting_send;
        outpos [outsize++] = 0xff;
        put_uint64 (&outpos [outsize], options.identity_size + 1);
        outsize += 8;
        outpos [outsize++] = 0x7f;
    }

    set_pollin (handle);
    set_pollout (handle);
    //  Flush all the data that may have been already received downstream.
    in_event ();
}
Beispiel #6
0
void zmq::pgm_sender_t::revive ()
{
    set_pollout (handle);
    out_event ();
}
Beispiel #7
0
void zmq::pgm_sender_t::activate_out ()
{
    set_pollout (handle);
    out_event ();
}
Beispiel #8
0
bool zmq::stream_engine_t::handshake ()
{
    zmq_assert (handshaking);
    zmq_assert (greeting_bytes_read < greeting_size);
    //  Receive the greeting.
    while (greeting_bytes_read < greeting_size) {
        const int n = read (greeting_recv + greeting_bytes_read,
                            greeting_size - greeting_bytes_read);
        if (n == -1) {
            error ();
            return false;
        }
        if (n == 0)
            return false;

        greeting_bytes_read += n;

        //  We have received at least one byte from the peer.
        //  If the first byte is not 0xff, we know that the
        //  peer is using unversioned protocol.
        if (greeting_recv [0] != 0xff)
            break;

        if (greeting_bytes_read < signature_size)
            continue;

        //  Inspect the right-most bit of the 10th byte (which coincides
        //  with the 'flags' field if a regular message was sent).
        //  Zero indicates this is a header of identity message
        //  (i.e. the peer is using the unversioned protocol).
        if (!(greeting_recv [9] & 0x01))
            break;

        //  The peer is using versioned protocol.
        //  Send the major version number.
        if (outpos + outsize == greeting_send + signature_size) {
            if (outsize == 0)
                set_pollout (handle);
            outpos [outsize++] = 3;     //  Major version number
        }

        if (greeting_bytes_read > signature_size) {
            if (outpos + outsize == greeting_send + signature_size + 1) {
                if (outsize == 0)
                    set_pollout (handle);

                //  Use ZMTP/2.0 to talk to older peers.
                if (greeting_recv [10] == ZMTP_1_0
                ||  greeting_recv [10] == ZMTP_2_0)
                    outpos [outsize++] = options.type;
                else {
                    outpos [outsize++] = 0; //  Minor version number
                    memset (outpos + outsize, 0, 20);

                    zmq_assert (options.mechanism == ZMQ_NULL
                            ||  options.mechanism == ZMQ_PLAIN
                            ||  options.mechanism == ZMQ_CURVE);

                    if (options.mechanism == ZMQ_NULL)
                        memcpy (outpos + outsize, "NULL", 4);
                    else
                    if (options.mechanism == ZMQ_PLAIN)
                        memcpy (outpos + outsize, "PLAIN", 5);
                    else
                        memcpy (outpos + outsize, "CURVE", 5);
                    outsize += 20;
                    memset (outpos + outsize, 0, 32);
                    outsize += 32;
                    greeting_size = v3_greeting_size;
                }
            }
        }
    }

    //  Position of the revision field in the greeting.
    const size_t revision_pos = 10;

    //  Is the peer using ZMTP/1.0 with no revision number?
    //  If so, we send and receive rest of identity message
    if (greeting_recv [0] != 0xff || !(greeting_recv [9] & 0x01)) {
        encoder = new (std::nothrow) v1_encoder_t (out_batch_size);
        alloc_assert (encoder);

        decoder = new (std::nothrow) v1_decoder_t (in_batch_size, options.maxmsgsize);
        alloc_assert (decoder);

        //  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.
        const size_t header_size = options.identity_size + 1 >= 255 ? 10 : 2;
        unsigned char tmp [10], *bufferp = tmp;
        size_t buffer_size = encoder->encode (&bufferp, header_size);
        zmq_assert (buffer_size == header_size);

        //  Make sure the decoder sees the data we have already received.
        inpos = greeting_recv;
        insize = greeting_bytes_read;

        //  To allow for interoperability with peers that do not forward
        //  their subscriptions, we inject a phantom subscription message
        //  message into the incoming message stream.
        if (options.type == ZMQ_PUB || options.type == ZMQ_XPUB)
            subscription_required = true;
    }
    else
    if (greeting_recv [revision_pos] == ZMTP_1_0) {
        encoder = new (std::nothrow) v1_encoder_t (
            out_batch_size);
        alloc_assert (encoder);

        decoder = new (std::nothrow) v1_decoder_t (
            in_batch_size, options.maxmsgsize);
        alloc_assert (decoder);
    }
    else
    if (greeting_recv [revision_pos] == ZMTP_2_0) {
        encoder = new (std::nothrow) v2_encoder_t (out_batch_size);
        alloc_assert (encoder);

        decoder = new (std::nothrow) v2_decoder_t (
            in_batch_size, options.maxmsgsize);
        alloc_assert (decoder);
    }
    else {
        encoder = new (std::nothrow) v2_encoder_t (out_batch_size);
        alloc_assert (encoder);

        decoder = new (std::nothrow) v2_decoder_t (
            in_batch_size, options.maxmsgsize);
        alloc_assert (decoder);

        if (memcmp (greeting_recv + 12, "NULL\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) == 0) {
            mechanism = new (std::nothrow)
                null_mechanism_t (session, peer_address, options);
            alloc_assert (mechanism);
        }
        else
        if (memcmp (greeting_recv + 12, "PLAIN\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) == 0) {
            mechanism = new (std::nothrow)
                plain_mechanism_t (session, peer_address, options);
            alloc_assert (mechanism);
        }
#ifdef HAVE_LIBSODIUM
        else
        if (memcmp (greeting_recv + 12, "CURVE\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) == 0) {
            if (options.as_server)
                mechanism = new (std::nothrow)
                    curve_server_t (session, peer_address, options);
            else
                mechanism = new (std::nothrow) curve_client_t (options);
            alloc_assert (mechanism);
        }
#endif
        else {
            error ();
            return false;
        }
        read_msg = &stream_engine_t::next_handshake_command;
        write_msg = &stream_engine_t::process_handshake_command;
    }

    // Start polling for output if necessary.
    if (outsize == 0)
        set_pollout (handle);

    //  Handshaking was successful.
    //  Switch into the normal message flow.
    handshaking = false;

    return true;
}
Beispiel #9
0
void zmq::socks_connecter_t::in_event ()
{
    zmq_assert (status != unplugged
             && status != waiting_for_reconnect_time);

    if (status == waiting_for_choice) {
        int rc = choice_decoder.input (s);
        if (rc == 0 || rc == -1)
            error ();
        else
        if (choice_decoder.message_ready ()) {
             const socks_choice_t choice = choice_decoder.decode ();
             rc = process_server_response (choice);
             if (rc == -1)
                 error ();
             else {
                 std::string hostname = "";
                 uint16_t port = 0;
                 if (parse_address (addr->address, hostname, port) == -1)
                     error ();
                 else {
                     request_encoder.encode (
                         socks_request_t (1, hostname, port));
                     reset_pollin (handle);
                     set_pollout (handle);
                     status = sending_request;
                 }
             }
        }
    }
    else
    if (status == waiting_for_response) {
        int rc = response_decoder.input (s);
        if (rc == 0 || rc == -1)
            error ();
        else
        if (response_decoder.message_ready ()) {
            const socks_response_t response = response_decoder.decode ();
            rc = process_server_response (response);
            if (rc == -1)
                error ();
            else {
                //  Create the engine object for this connection.
                stream_engine_t *engine = new (std::nothrow)
                    stream_engine_t (s, options, endpoint);
                alloc_assert (engine);

                //  Attach the engine to the corresponding session object.
                send_attach (session, engine);

                socket->event_connected (endpoint, (int) s);

                rm_fd (handle);
                s = -1;
                status = unplugged;

                //  Shut the connecter down.
                terminate ();
            }
        }
    }
    else
        error ();
}
Beispiel #10
0
bool zmq::stream_engine_t::handshake ()
{
    zmq_assert (handshaking);
    zmq_assert (greeting_bytes_read < greeting_size);

    //  Receive the greeting.
    while (greeting_bytes_read < greeting_size) {
        const int n = read (greeting + greeting_bytes_read,
                            greeting_size - greeting_bytes_read);
        if (n == -1) {
            error ();
            return false;
        }

        if (n == 0)
            return false;

        greeting_bytes_read += n;

        //  We have received at least one byte from the peer.
        //  If the first byte is not 0xff, we know that the
        //  peer is using unversioned protocol.
        if (greeting [0] != 0xff)
            break;

        if (greeting_bytes_read < 10)
            continue;

        //  Inspect the right-most bit of the 10th byte (which coincides
        //  with the 'flags' field if a regular message was sent).
        //  Zero indicates this is a header of identity message
        //  (i.e. the peer is using the unversioned protocol).
        if (!(greeting [9] & 0x01))
            break;

        //  The peer is using versioned protocol.
        //  Send the rest of the greeting, if necessary.
        if (outpos + outsize != greeting_output_buffer + greeting_size) {
            if (outsize == 0)
                set_pollout (handle);
            outpos [outsize++] = 1;             // Protocol version
            outpos [outsize++] = options.type;  // Socket type
        }
    }

    //  Position of the version field in the greeting.
    const size_t version_pos = 10;

    //  Is the peer using the unversioned protocol?
    //  If so, we send and receive rests of identity
    //  messages.
    if (greeting [0] != 0xff || !(greeting [9] & 0x01)) {
        encoder = new (std::nothrow) encoder_t (out_batch_size);
        alloc_assert (encoder);
        encoder->set_msg_source (session);

        decoder = new (std::nothrow) decoder_t (in_batch_size, options.maxmsgsize);
        alloc_assert (decoder);
        decoder->set_msg_sink (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.
        const size_t header_size = options.identity_size + 1 >= 255 ? 10 : 2;
        unsigned char tmp [10], *bufferp = tmp;
        size_t buffer_size = header_size;
        encoder->get_data (&bufferp, &buffer_size);
        zmq_assert (buffer_size == header_size);

        //  Make sure the decoder sees the data we have already received.
        inpos = greeting;
        insize = greeting_bytes_read;

        //  To allow for interoperability with peers that do not forward
        //  their subscriptions, we inject a phony subsription
        //  message into the incomming message stream. To put this
        //  message right after the identity message, we temporarily
        //  divert the message stream from session to ourselves.
        if (options.type == ZMQ_PUB || options.type == ZMQ_XPUB)
            decoder->set_msg_sink (this);
    }
    else
    if (greeting [version_pos] == 0) {
        //  ZMTP/1.0 framing.
        encoder = new (std::nothrow) encoder_t (out_batch_size);
        alloc_assert (encoder);
        encoder->set_msg_source (session);

        decoder = new (std::nothrow) decoder_t (in_batch_size, options.maxmsgsize);
        alloc_assert (decoder);
        decoder->set_msg_sink (session);
    }
    else {
        //  v1 framing protocol.
        encoder = new (std::nothrow) v1_encoder_t (out_batch_size, session);
        alloc_assert (encoder);

        decoder = new (std::nothrow)
            v1_decoder_t (in_batch_size, options.maxmsgsize, session);
        alloc_assert (decoder);
    }

    // Start polling for output if necessary.
    if (outsize == 0)
        set_pollout (handle);

    //  Handshaking was successful.
    //  Switch into the normal message flow.
    handshaking = false;

    return true;
}
Beispiel #11
0
void zmq::pgm_sender_t::out_event ()
{
    //  POLLOUT event from send socket. If write buffer is empty,
    //  try to read new data from the encoder.
    if (write_size == 0) {

        //  First two bytes (sizeof uint16_t) are used to store message
        //  offset in following steps. Note that by passing our buffer to
        //  the get data function we prevent it from returning its own buffer.
        unsigned char *bf = out_buffer + sizeof (uint16_t);
        size_t bfsz = out_buffer_size - sizeof (uint16_t);
        uint16_t offset = 0xffff;

        size_t bytes = encoder.encode (&bf, bfsz);
        while (bytes < bfsz) {
            if (!more_flag && offset == 0xffff)
                offset = static_cast <uint16_t> (bytes);
            int rc = session->pull_msg (&msg);
            if (rc == -1)
                break;
            more_flag = msg.flags () & msg_t::more;
            encoder.load_msg (&msg);
            bf = out_buffer + sizeof (uint16_t) + bytes;
            bytes += encoder.encode (&bf, bfsz - bytes);
        }

        //  If there are no data to write stop polling for output.
        if (bytes == 0) {
            reset_pollout (handle);
            return;
        }

        write_size = sizeof (uint16_t) + bytes;

        //  Put offset information in the buffer.
        put_uint16 (out_buffer, offset);
    }

    if (has_tx_timer) {
        cancel_timer (tx_timer_id);
        set_pollout (handle);
        has_tx_timer = false;
    }

    //  Send the data.
    size_t nbytes = pgm_socket.send (out_buffer, write_size);

    //  We can write either all data or 0 which means rate limit reached.
    if (nbytes == write_size)
        write_size = 0;
    else {
        zmq_assert (nbytes == 0);

        if (errno == ENOMEM) {
            // Stop polling handle and wait for tx timeout
            const long timeout = pgm_socket.get_tx_timeout ();
            add_timer (timeout, tx_timer_id);
            reset_pollout (handle);
            has_tx_timer = true;
        }
        else
            errno_assert (errno == EBUSY);
    }
}
Beispiel #12
0
void zmq::pgm_sender_t::restart_output ()
{
    set_pollout (handle);
    out_event ();
}
Beispiel #13
0
bool zmq::stream_engine_t::handshake ()
{
    zmq_assert (_handshaking);
    zmq_assert (_greeting_bytes_read < _greeting_size);
    //  Receive the greeting.
    while (_greeting_bytes_read < _greeting_size) {
        const int n = tcp_read (_s, _greeting_recv + _greeting_bytes_read,
                                _greeting_size - _greeting_bytes_read);
        if (n == 0) {
            errno = EPIPE;
            error (connection_error);
            return false;
        }
        if (n == -1) {
            if (errno != EAGAIN)
                error (connection_error);
            return false;
        }

        _greeting_bytes_read += n;

        //  We have received at least one byte from the peer.
        //  If the first byte is not 0xff, we know that the
        //  peer is using unversioned protocol.
        if (_greeting_recv[0] != 0xff)
            break;

        if (_greeting_bytes_read < signature_size)
            continue;

        //  Inspect the right-most bit of the 10th byte (which coincides
        //  with the 'flags' field if a regular message was sent).
        //  Zero indicates this is a header of a routing id message
        //  (i.e. the peer is using the unversioned protocol).
        if (!(_greeting_recv[9] & 0x01))
            break;

        //  The peer is using versioned protocol.
        //  Send the major version number.
        if (_outpos + _outsize == _greeting_send + signature_size) {
            if (_outsize == 0)
                set_pollout (_handle);
            _outpos[_outsize++] = 3; //  Major version number
        }

        if (_greeting_bytes_read > signature_size) {
            if (_outpos + _outsize == _greeting_send + signature_size + 1) {
                if (_outsize == 0)
                    set_pollout (_handle);

                //  Use ZMTP/2.0 to talk to older peers.
                if (_greeting_recv[10] == ZMTP_1_0
                    || _greeting_recv[10] == ZMTP_2_0)
                    _outpos[_outsize++] = _options.type;
                else {
                    _outpos[_outsize++] = 0; //  Minor version number
                    memset (_outpos + _outsize, 0, 20);

                    zmq_assert (_options.mechanism == ZMQ_NULL
                                || _options.mechanism == ZMQ_PLAIN
                                || _options.mechanism == ZMQ_CURVE
                                || _options.mechanism == ZMQ_GSSAPI);

                    if (_options.mechanism == ZMQ_NULL)
                        memcpy (_outpos + _outsize, "NULL", 4);
                    else if (_options.mechanism == ZMQ_PLAIN)
                        memcpy (_outpos + _outsize, "PLAIN", 5);
                    else if (_options.mechanism == ZMQ_GSSAPI)
                        memcpy (_outpos + _outsize, "GSSAPI", 6);
                    else if (_options.mechanism == ZMQ_CURVE)
                        memcpy (_outpos + _outsize, "CURVE", 5);
                    _outsize += 20;
                    memset (_outpos + _outsize, 0, 32);
                    _outsize += 32;
                    _greeting_size = v3_greeting_size;
                }
            }
        }
    }

    //  Position of the revision field in the greeting.
    const size_t revision_pos = 10;

    //  Is the peer using ZMTP/1.0 with no revision number?
    //  If so, we send and receive rest of routing id message
    if (_greeting_recv[0] != 0xff || !(_greeting_recv[9] & 0x01)) {
        if (_session->zap_enabled ()) {
            // reject ZMTP 1.0 connections if ZAP is enabled
            error (protocol_error);
            return false;
        }

        _encoder = new (std::nothrow) v1_encoder_t (out_batch_size);
        alloc_assert (_encoder);

        _decoder =
          new (std::nothrow) v1_decoder_t (in_batch_size, _options.maxmsgsize);
        alloc_assert (_decoder);

        //  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.
        const size_t header_size =
          _options.routing_id_size + 1 >= UCHAR_MAX ? 10 : 2;
        unsigned char tmp[10], *bufferp = tmp;

        //  Prepare the routing id message and load it into encoder.
        //  Then consume bytes we have already sent to the peer.
        const int rc = _tx_msg.init_size (_options.routing_id_size);
        zmq_assert (rc == 0);
        memcpy (_tx_msg.data (), _options.routing_id, _options.routing_id_size);
        _encoder->load_msg (&_tx_msg);
        size_t buffer_size = _encoder->encode (&bufferp, header_size);
        zmq_assert (buffer_size == header_size);

        //  Make sure the decoder sees the data we have already received.
        _inpos = _greeting_recv;
        _insize = _greeting_bytes_read;

        //  To allow for interoperability with peers that do not forward
        //  their subscriptions, we inject a phantom subscription message
        //  message into the incoming message stream.
        if (_options.type == ZMQ_PUB || _options.type == ZMQ_XPUB)
            _subscription_required = true;

        //  We are sending our routing id now and the next message
        //  will come from the socket.
        _next_msg = &stream_engine_t::pull_msg_from_session;

        //  We are expecting routing id message.
        _process_msg = &stream_engine_t::process_routing_id_msg;
    } else if (_greeting_recv[revision_pos] == ZMTP_1_0) {
        if (_session->zap_enabled ()) {
            // reject ZMTP 1.0 connections if ZAP is enabled
            error (protocol_error);
            return false;
        }

        _encoder = new (std::nothrow) v1_encoder_t (out_batch_size);
        alloc_assert (_encoder);

        _decoder =
          new (std::nothrow) v1_decoder_t (in_batch_size, _options.maxmsgsize);
        alloc_assert (_decoder);
    } else if (_greeting_recv[revision_pos] == ZMTP_2_0) {
        if (_session->zap_enabled ()) {
            // reject ZMTP 2.0 connections if ZAP is enabled
            error (protocol_error);
            return false;
        }

        _encoder = new (std::nothrow) v2_encoder_t (out_batch_size);
        alloc_assert (_encoder);

        _decoder = new (std::nothrow)
          v2_decoder_t (in_batch_size, _options.maxmsgsize, _options.zero_copy);
        alloc_assert (_decoder);
    } else {
        _encoder = new (std::nothrow) v2_encoder_t (out_batch_size);
        alloc_assert (_encoder);

        _decoder = new (std::nothrow)
          v2_decoder_t (in_batch_size, _options.maxmsgsize, _options.zero_copy);
        alloc_assert (_decoder);

        if (_options.mechanism == ZMQ_NULL
            && memcmp (_greeting_recv + 12,
                       "NULL\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20)
                 == 0) {
            _mechanism = new (std::nothrow)
              null_mechanism_t (_session, _peer_address, _options);
            alloc_assert (_mechanism);
        } else if (_options.mechanism == ZMQ_PLAIN
                   && memcmp (_greeting_recv + 12,
                              "PLAIN\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20)
                        == 0) {
            if (_options.as_server)
                _mechanism = new (std::nothrow)
                  plain_server_t (_session, _peer_address, _options);
            else
                _mechanism =
                  new (std::nothrow) plain_client_t (_session, _options);
            alloc_assert (_mechanism);
        }
#ifdef ZMQ_HAVE_CURVE
        else if (_options.mechanism == ZMQ_CURVE
                 && memcmp (_greeting_recv + 12,
                            "CURVE\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20)
                      == 0) {
            if (_options.as_server)
                _mechanism = new (std::nothrow)
                  curve_server_t (_session, _peer_address, _options);
            else
                _mechanism =
                  new (std::nothrow) curve_client_t (_session, _options);
            alloc_assert (_mechanism);
        }
#endif
#ifdef HAVE_LIBGSSAPI_KRB5
        else if (_options.mechanism == ZMQ_GSSAPI
                 && memcmp (_greeting_recv + 12,
                            "GSSAPI\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20)
                      == 0) {
            if (_options.as_server)
                _mechanism = new (std::nothrow)
                  gssapi_server_t (_session, _peer_address, _options);
            else
                _mechanism =
                  new (std::nothrow) gssapi_client_t (_session, _options);
            alloc_assert (_mechanism);
        }
#endif
        else {
            _session->get_socket ()->event_handshake_failed_protocol (
              _session->get_endpoint (),
              ZMQ_PROTOCOL_ERROR_ZMTP_MECHANISM_MISMATCH);
            error (protocol_error);
            return false;
        }
        _next_msg = &stream_engine_t::next_handshake_command;
        _process_msg = &stream_engine_t::process_handshake_command;
    }

    // Start polling for output if necessary.
    if (_outsize == 0)
        set_pollout (_handle);

    //  Handshaking was successful.
    //  Switch into the normal message flow.
    _handshaking = false;

    if (_has_handshake_timer) {
        cancel_timer (handshake_timer_id);
        _has_handshake_timer = false;
    }

    return true;
}
Beispiel #14
0
void xs::pgm_sender_t::activate_out ()
{
    set_pollout (handle);
    out_event (retired_fd);
}
Beispiel #15
0
void zmq::udp_engine_t::plug (io_thread_t *io_thread_, session_base_t *session_)
{
    zmq_assert (!plugged);
    plugged = true;

    zmq_assert (!session);
    zmq_assert (session_);
    session = session_;

    //  Connect to I/O threads poller object.
    io_object_t::plug (io_thread_);
    handle = add_fd (fd);

    // Bind the socket to a device if applicable
    if (!options.bound_device.empty ())
        bind_to_device (fd, options.bound_device);

    if (send_enabled) {
        if (!options.raw_socket) {
            out_address = address->resolved.udp_addr->dest_addr ();
            out_addrlen = address->resolved.udp_addr->dest_addrlen ();
        } else {
            out_address = (sockaddr *) &raw_address;
            out_addrlen = sizeof (sockaddr_in);
        }

        set_pollout (handle);
    }

    if (recv_enabled) {
        int on = 1;
        int rc =
          setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, (char *) &on, sizeof (on));
#ifdef ZMQ_HAVE_WINDOWS
        wsa_assert (rc != SOCKET_ERROR);
#else
        errno_assert (rc == 0);
#endif

#ifdef ZMQ_HAVE_VXWORKS
        rc = bind (fd, (sockaddr *) address->resolved.udp_addr->bind_addr (),
                   address->resolved.udp_addr->bind_addrlen ());
#else
        rc = bind (fd, address->resolved.udp_addr->bind_addr (),
                   address->resolved.udp_addr->bind_addrlen ());
#endif
#ifdef ZMQ_HAVE_WINDOWS
        wsa_assert (rc != SOCKET_ERROR);
#else
        errno_assert (rc == 0);
#endif

        if (address->resolved.udp_addr->is_mcast ()) {
            struct ip_mreq mreq;
            mreq.imr_multiaddr = address->resolved.udp_addr->multicast_ip ();
            mreq.imr_interface = address->resolved.udp_addr->interface_ip ();
            rc = setsockopt (fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *) &mreq,
                             sizeof (mreq));
#ifdef ZMQ_HAVE_WINDOWS
            wsa_assert (rc != SOCKET_ERROR);
#else
            errno_assert (rc == 0);
#endif
        }
        set_pollin (handle);

        //  Call restart output to drop all join/leave commands
        restart_output ();
    }
}