Esempio n. 1
0
void zmq::stream_t::identify_peer (pipe_t *pipe_)
{
    //  Always assign identity for raw-socket
    unsigned char buffer [5];
    buffer [0] = 0;
    blob_t identity;
    if (connect_rid.length ()) {
        identity = blob_t ((unsigned char*) connect_rid.c_str(),
            connect_rid.length ());
        connect_rid.clear ();
        outpipes_t::iterator it = outpipes.find (identity);
        zmq_assert (it == outpipes.end ());
    }
    else {
        put_uint32 (buffer + 1, next_rid++);
        identity = blob_t (buffer, sizeof buffer);
        memcpy (options.identity, identity.data (), identity.size ());
        options.identity_size = (unsigned char) identity.size ();
    }
    pipe_->set_identity (identity);
    //  Add the record into output pipes lookup table
    outpipe_t outpipe = {pipe_, true};
    const bool ok = outpipes.insert (
        outpipes_t::value_type (identity, outpipe)).second;
    zmq_assert (ok);
}
Esempio n. 2
0
void zmq::xpub_t::xread_activated (pipe_t *pipe_)
{
    //  There are some subscriptions waiting. Let's process them.
    msg_t sub;
    while (pipe_->read (&sub)) {

        //  Apply the subscription to the trie.
        unsigned char *const data = (unsigned char*) sub.data ();
        const size_t size = sub.size ();
        if (size > 0 && (*data == 0 || *data == 1)) {
            bool unique;
            if (*data == 0)
                unique = subscriptions.rm (data + 1, size - 1, pipe_);
            else
                unique = subscriptions.add (data + 1, size - 1, pipe_);

            //  If the subscription is not a duplicate store it so that it can be
            //  passed to used on next recv call. (Unsubscribe is not verbose.)
            if (options.type == ZMQ_XPUB && (unique || (*data && verbose)))
                pending.push_back (blob_t (data, size));
        }
	else 
            //  Process user message coming upstream from xsub socket
	    pending.push_back (blob_t (data, size));

        sub.close ();
    }
}
Esempio n. 3
0
void zmq::xpub_t::xread_activated (pipe_t *pipe_)
{
    //  There are some subscriptions waiting. Let's process them.
    msg_t sub;
    while (pipe_->read (&sub)) {
        //  Apply the subscription to the trie
        unsigned char *const data = (unsigned char *) sub.data ();
        const size_t size = sub.size ();
        metadata_t *metadata = sub.metadata ();
        if (size > 0 && (*data == 0 || *data == 1)) {
            if (manual) {
                // Store manual subscription to use on termination
                if (*data == 0)
                    manual_subscriptions.rm (data + 1, size - 1, pipe_);
                else
                    manual_subscriptions.add (data + 1, size - 1, pipe_);

                pending_pipes.push_back (pipe_);
                pending_data.push_back (blob_t (data, size));
                if (metadata)
                    metadata->add_ref ();
                pending_metadata.push_back (metadata);
                pending_flags.push_back (0);
            } else {
                bool notify;
                if (*data == 0) {
                    mtrie_t::rm_result rm_result =
                      subscriptions.rm (data + 1, size - 1, pipe_);
                    //  TODO reconsider what to do if rm_result == mtrie_t::not_found
                    notify =
                      rm_result != mtrie_t::values_remain || verbose_unsubs;
                } else {
                    bool first_added =
                      subscriptions.add (data + 1, size - 1, pipe_);
                    notify = first_added || verbose_subs;
                }

                //  If the request was a new subscription, or the subscription
                //  was removed, or verbose mode is enabled, store it so that
                //  it can be passed to the user on next recv call.
                if (options.type == ZMQ_XPUB && notify) {
                    pending_data.push_back (blob_t (data, size));
                    if (metadata)
                        metadata->add_ref ();
                    pending_metadata.push_back (metadata);
                    pending_flags.push_back (0);
                }
            }
        } else {
            //  Process user message coming upstream from xsub socket
            pending_data.push_back (blob_t (data, size));
            if (metadata)
                metadata->add_ref ();
            pending_metadata.push_back (metadata);
            pending_flags.push_back (sub.flags ());
        }
        sub.close ();
    }
}
Esempio n. 4
0
bool zmq::router_t::identify_peer (pipe_t *pipe_)
{
    msg_t msg;
    blob_t identity;
    bool ok;

    if (options.raw_sock) { //  Always assign identity for raw-socket
        unsigned char buf [5];
        buf [0] = 0;
        put_uint32 (buf + 1, next_peer_id++);
        identity = blob_t (buf, sizeof buf);
        unsigned int i = 0;  // Store identity to allow use of raw socket as client
        for (blob_t::iterator it = identity.begin(); it != identity.end(); it++) options.identity[i++] = *it;
        options.identity_size = i;
    }
    else {
        msg.init ();
        ok = pipe_->read (&msg);
        if (!ok)
            return false;

        if (msg.size () == 0) {
            //  Fall back on the auto-generation
            unsigned char buf [5];
            buf [0] = 0;
            put_uint32 (buf + 1, next_peer_id++);
            identity = blob_t (buf, sizeof buf);
            msg.close ();
        }
        else {
            identity = blob_t ((unsigned char*) msg.data (), msg.size ());
            outpipes_t::iterator it = outpipes.find (identity);
            msg.close ();

            //  Ignore peers with duplicate ID.
            if (it != outpipes.end ())
                return false;
        }
    }

    pipe_->set_identity (identity);
    //  Add the record into output pipes lookup table
    outpipe_t outpipe = {pipe_, true};
    ok = outpipes.insert (outpipes_t::value_type (identity, outpipe)).second;
    zmq_assert (ok);

    return true;
}
Esempio n. 5
0
void zmq::mechanism_t::set_user_id (const void *data_, size_t size_)
{
    user_id = blob_t (static_cast <const unsigned char*> (data_), size_);
    zap_properties.insert (
        metadata_t::dict_t::value_type (
            "User-Id", std::string ((char *) data_, size_)));
}
Esempio n. 6
0
int zmq::router_t::xgetsockopt (int option_, const void *optval_,
    size_t *optvallen_)
{
    switch (option_) {
        case ZMQ_IDENTITY_FD:
            if (optval_==NULL && optvallen_) {
                *optvallen_=sizeof(fd_t);
                return 0;
            }
            if (optval_ && optvallen_ && *optvallen_) {
                blob_t identity= blob_t((unsigned char*)optval_,*optvallen_);
                outpipes_t::iterator it = outpipes.find (identity);
                if (it == outpipes.end() ){
                    return ENOTSOCK;
                }
                *((fd_t*)optval_)=it->second.pipe->assoc_fd;
                *optvallen_=sizeof(fd_t);
                return 0;
            }
            break;
        default:
            break;
    }
    errno = EINVAL;
    return -1;
}
Esempio n. 7
0
void zmq::xpub_t::xread_activated (pipe_t *pipe_)
{
    //  There are some subscriptions waiting. Let's process them.
    msg_t sub;
    while (pipe_->read (&sub)) {

        //  Apply the subscription to the trie.
        unsigned char *const data = (unsigned char*) sub.data ();
        const size_t size = sub.size ();
        if (size > 0 && (*data == 0 || *data == 1)) {
            bool unique;
            if (*data == 0)
                unique = subscriptions.rm (data + 1, size - 1, pipe_);
            else
                unique = subscriptions.add (data + 1, size - 1, pipe_);

            //  If the subscription is not a duplicate store it so that it can be
            //  passed to used on next recv call.
            if (unique && options.type != ZMQ_PUB)
                pending.push_back (blob_t (data, size));
        }

        sub.close ();
    }
}
Esempio n. 8
0
void zmq::xpub_t::xread_activated (pipe_t *pipe_)
{
    //  There are some subscriptions waiting. Let's process them.
    msg_t sub;
    while (pipe_->read (&sub)) {
        //  Apply the subscription to the trie
        unsigned char *const data = (unsigned char *) sub.data ();
        const size_t size = sub.size ();
        if (size > 0 && (*data == 0 || *data == 1)) {
            if (manual)
            {
                pending_pipes.push_back(pipe_);
                pending_data.push_back(blob_t(data, size));
                pending_metadata.push_back(sub.metadata());
                pending_flags.push_back(0);
            }
            else
            {
                bool unique;
                if (*data == 0)
                    unique = subscriptions.rm(data + 1, size - 1, pipe_);
                else
                    unique = subscriptions.add(data + 1, size - 1, pipe_);

                //  If the (un)subscription is not a duplicate store it so that it can be
                //  passed to the user on next recv call unless verbose mode is enabled
                //  which makes to pass always these messages.
                if (options.type == ZMQ_XPUB && (unique || (*data == 1 && verbose_subs) ||
                        (*data == 0 && verbose_unsubs && verbose_subs))) {
                    pending_data.push_back(blob_t(data, size));
                    pending_metadata.push_back(sub.metadata());
                    pending_flags.push_back(0);
                }
            }
        }
        else {
            //  Process user message coming upstream from xsub socket
            pending_data.push_back (blob_t (data, size));
            pending_metadata.push_back (sub.metadata ());
            pending_flags.push_back (sub.flags ());
        }
        sub.close ();
    }
}
Esempio n. 9
0
void zmq::zmq_init_t::detach ()
{
    //  This function is called by engine when disconnection occurs.

    //  If there is an associated session, send it a null engine to let it know
    //  that connection process was unsuccesful.
    if (session)
        send_attach (session, NULL, blob_t (), true);

    //  The engine will destroy itself, so let's just drop the pointer here and
    //  start termination of the init object.
    engine = NULL;
    terminate ();
}
Esempio n. 10
0
bool zmq::router_t::identify_peer (pipe_t *pipe_)
{
    msg_t msg;
    blob_t identity;

    msg.init ();
    bool ok = pipe_->read (&msg);
    if (!ok)
        return false;

    if (msg.size () == 0) {
        //  Fall back on the auto-generation
        unsigned char buf [5];
        buf [0] = 0;
        put_uint32 (buf + 1, next_peer_id++);
        identity = blob_t (buf, sizeof buf);
        msg.close ();
    }
    else {
        identity = blob_t ((unsigned char*) msg.data (), msg.size ());
        outpipes_t::iterator it = outpipes.find (identity);
        msg.close ();

        //  Ignore peers with duplicate ID.
        if (it != outpipes.end ())
            return false;
    }

    pipe_->set_identity (identity);
    //  Add the record into output pipes lookup table
    outpipe_t outpipe = {pipe_, true};
    ok = outpipes.insert (outpipes_t::value_type (identity, outpipe)).second;
    zmq_assert (ok);

    return true;
}
Esempio n. 11
0
inline int get_data_blob::operator()(int req, size_t col, variant& var)
{
  T_CCI_BIT data;
  int ind(-1);
  const int r(lib::singleton().p_cci_get_data(req, int(col + 1), CCI_A_TYPE_BIT, &data, &ind));
  if (lib::error(r) || ind < 0)
    var = null_t();
  else
  {
    var = blob_t();
    blob_t& blob(::boost::get<blob_t>(var));
    blob.resize(data.size);
    if (!blob.empty()) memcpy(blob.data(), data.buf, data.size);
  }
  return r;
} // get_data_blob::
Esempio n. 12
0
bool zmq::pipe_t::read (msg_t *msg_)
{
    if (unlikely (!in_active))
        return false;
    if (unlikely (state != active && state != waiting_for_delimiter))
        return false;

read_message:
    if (!inpipe->read (msg_)) {
        in_active = false;
        return false;
    }

    //  If this is a credential, save a copy and receive next message.
    if (unlikely (msg_->is_credential ())) {
        const unsigned char *data = static_cast <const unsigned char *> (msg_->data ());
        credential = blob_t (data, msg_->size ());
        const int rc = msg_->close ();
        zmq_assert (rc == 0);
        goto read_message;
    }

    //  If delimiter was read, start termination process of the pipe.
    if (msg_->is_delimiter ()) {
        process_delimiter ();
        return false;
    }

    if (!(msg_->flags () & msg_t::more) && !msg_->is_identity ())
        msgs_read++;

    if (lwm > 0 && msgs_read % lwm == 0)
        send_activate_write (peer, msgs_read);

    return true;
}
zmq::blob_t zmq::socket_base_t::get_credential () const
{
    return blob_t ();
}
Esempio n. 14
0
int zmq::socket_base_t::connect (const char *addr_)
{
    if (unlikely (ctx_terminated)) {
        errno = ETERM;
        return -1;
    }

    //  Parse addr_ string.
    std::string protocol;
    std::string address;
    int rc = parse_uri (addr_, protocol, address);
    if (rc != 0)
        return -1;

    rc = check_protocol (protocol);
    if (rc != 0)
        return -1;

    if (protocol == "inproc" || protocol == "sys") {

        //  TODO: inproc connect is specific with respect to creating pipes
        //  as there's no 'reconnect' functionality implemented. Once that
        //  is in place we should follow generic pipe creation algorithm.

        //  Find the peer endpoint.
        endpoint_t peer = find_endpoint (addr_);
        if (!peer.socket)
            return -1;

        reader_t *inpipe_reader = NULL;
        writer_t *inpipe_writer = NULL;
        reader_t *outpipe_reader = NULL;
        writer_t *outpipe_writer = NULL;

        // The total HWM for an inproc connection should be the sum of
        // the binder's HWM and the connector's HWM.  (Similarly for the
        // SWAP.)
        int64_t  hwm;
        if (options.hwm == 0 || peer.options.hwm == 0)
            hwm = 0;
        else
            hwm = options.hwm + peer.options.hwm;
        int64_t swap;
        if (options.swap == 0 && peer.options.swap == 0)
            swap = 0;
        else
            swap = options.swap + peer.options.swap;

        //  Create inbound pipe, if required.
        if (options.requires_in)
            create_pipe (this, peer.socket, hwm, swap,
                &inpipe_reader, &inpipe_writer);

        //  Create outbound pipe, if required.
        if (options.requires_out)
            create_pipe (peer.socket, this, hwm, swap,
                &outpipe_reader, &outpipe_writer);

        //  Attach the pipes to this socket object.
        attach_pipes (inpipe_reader, outpipe_writer, peer.options.identity);

        //  Attach the pipes to the peer socket. Note that peer's seqnum
        //  was incremented in find_endpoint function. We don't need it
        //  increased here.
        send_bind (peer.socket, outpipe_reader, inpipe_writer,
            options.identity, false);

        return 0;
    }

    //  Choose the I/O thread to run the session in.
    io_thread_t *io_thread = choose_io_thread (options.affinity);
    if (!io_thread) {
        errno = EMTHREAD;
        return -1;
    }

    //  Create session.
    connect_session_t *session = new (std::nothrow) connect_session_t (
        io_thread, this, options, protocol.c_str (), address.c_str ());
    alloc_assert (session);

    //  If 'immediate connect' feature is required, we'll create the pipes
    //  to the session straight away. Otherwise, they'll be created by the
    //  session once the connection is established.
    if (options.immediate_connect) {

        reader_t *inpipe_reader = NULL;
        writer_t *inpipe_writer = NULL;
        reader_t *outpipe_reader = NULL;
        writer_t *outpipe_writer = NULL;

        //  Create inbound pipe, if required.
        if (options.requires_in)
            create_pipe (this, session, options.hwm, options.swap,
                &inpipe_reader, &inpipe_writer);

        //  Create outbound pipe, if required.
        if (options.requires_out)
            create_pipe (session, this, options.hwm, options.swap,
                &outpipe_reader, &outpipe_writer);

        //  Attach the pipes to the socket object.
        attach_pipes (inpipe_reader, outpipe_writer, blob_t ());

        //  Attach the pipes to the session object.
        session->attach_pipes (outpipe_reader, inpipe_writer, blob_t ());
    }

    //  Activate the session. Make it a child of this socket.
    launch_child (session);

    return 0;
}
Esempio n. 15
0
bool zmq::router_t::identify_peer (pipe_t *pipe_)
{
    msg_t msg;
    blob_t identity;
    bool ok;

    if (connect_rid.length()) {
        identity = blob_t ((unsigned char*) connect_rid.c_str (),
            connect_rid.length());
        connect_rid.clear ();
        outpipes_t::iterator it = outpipes.find (identity);
        if (it != outpipes.end ()) 
            zmq_assert(false); //  Not allowed to duplicate an existing rid
    }
    else 
    if (options.raw_sock) { //  Always assign identity for raw-socket
        unsigned char buf [5];
        buf [0] = 0;
        put_uint32 (buf + 1, next_rid++);
        identity = blob_t (buf, sizeof buf);
    }
    else
    if (!options.raw_sock) { 
        //  Pick up handshake cases and also case where next identity is set
        msg.init ();
        ok = pipe_->read (&msg);
        if (!ok)
            return false;

        if (msg.size () == 0) {
            //  Fall back on the auto-generation
            unsigned char buf [5];
            buf [0] = 0;
            put_uint32 (buf + 1, next_rid++);
            identity = blob_t (buf, sizeof buf);
            msg.close ();
        }
        else {
            identity = blob_t ((unsigned char*) msg.data (), msg.size ());
            outpipes_t::iterator it = outpipes.find (identity);
            msg.close ();

            if (it != outpipes.end ()) {
                if (!handover)
                    //  Ignore peers with duplicate ID
                    return false;
                else {
                    //  We will allow the new connection to take over this
                    //  identity. Temporarily assign a new identity to the 
                    //  existing pipe so we can terminate it asynchronously.
                    unsigned char buf [5];
                    buf [0] = 0;
                    put_uint32 (buf + 1, next_rid++);
                    blob_t new_identity = blob_t (buf, sizeof buf);

                    it->second.pipe->set_identity (new_identity);
                    outpipe_t existing_outpipe = 
                        {it->second.pipe, it->second.active};
                
                    ok = outpipes.insert (outpipes_t::value_type (
                        new_identity, existing_outpipe)).second;
                    zmq_assert (ok);
                
                    //  Remove the existing identity entry to allow the new
                    //  connection to take the identity.
                    outpipes.erase (it);

                    existing_outpipe.pipe->terminate (true);
                }
            }
        }
    }

    pipe_->set_identity (identity);
    //  Add the record into output pipes lookup table
    outpipe_t outpipe = {pipe_, true};
    ok = outpipes.insert (outpipes_t::value_type (identity, outpipe)).second;
    zmq_assert (ok);

    return true;
}
Esempio n. 16
0
int zmq::socket_base_t::connect (const char *addr_)
{
    if (unlikely (ctx_terminated)) {
        errno = ETERM;
        return -1;
    }

    //  Parse addr_ string.
    std::string protocol;
    std::string address;
    int rc = parse_uri (addr_, protocol, address);
    if (rc != 0)
        return -1;

    //  Checks that protocol is valid and supported on this system
    rc = check_protocol (protocol);
    if (rc != 0)
        return -1;

    //  Parsed address for validation
    sockaddr_storage addr;
    socklen_t addr_len;

    if (protocol == "tcp")
        rc = resolve_ip_hostname (&addr, &addr_len, address.c_str ());
    else
    if (protocol == "ipc")
        rc = resolve_local_path (&addr, &addr_len, address.c_str ());
    if (rc != 0)
        return -1;

    if (protocol == "inproc" || protocol == "sys") {

        //  TODO: inproc connect is specific with respect to creating pipes
        //  as there's no 'reconnect' functionality implemented. Once that
        //  is in place we should follow generic pipe creation algorithm.

        //  Find the peer endpoint.
        endpoint_t peer = find_endpoint (addr_);
        if (!peer.socket)
            return -1;

        // The total HWM for an inproc connection should be the sum of
        // the binder's HWM and the connector's HWM.
        int  sndhwm;
        int  rcvhwm;
        if (options.sndhwm == 0 || peer.options.rcvhwm == 0)
            sndhwm = 0;
        else
            sndhwm = options.sndhwm + peer.options.rcvhwm;
        if (options.rcvhwm == 0 || peer.options.sndhwm == 0)
            rcvhwm = 0;
        else
            rcvhwm = options.rcvhwm + peer.options.sndhwm;

        //  Create a bi-directional pipe to connect the peers.
        object_t *parents [2] = {this, peer.socket};
        pipe_t *pipes [2] = {NULL, NULL};
        int hwms [2] = {sndhwm, rcvhwm};
        bool delays [2] = {options.delay_on_disconnect, options.delay_on_close};
        int rc = pipepair (parents, pipes, hwms, delays);
        errno_assert (rc == 0);

        //  Attach local end of the pipe to this socket object.
        attach_pipe (pipes [0], peer.options.identity);

        //  Attach remote end of the pipe to the peer socket. Note that peer's
        //  seqnum was incremented in find_endpoint function. We don't need it
        //  increased here.
        send_bind (peer.socket, pipes [1], options.identity, false);

        return 0;
    }

    //  Choose the I/O thread to run the session in.
    io_thread_t *io_thread = choose_io_thread (options.affinity);
    if (!io_thread) {
        errno = EMTHREAD;
        return -1;
    }

    //  Create session.
    connect_session_t *session = new (std::nothrow) connect_session_t (
        io_thread, this, options, protocol.c_str (), address.c_str ());
    alloc_assert (session);

    //  If 'immediate connect' feature is required, we'll create the pipes
    //  to the session straight away. Otherwise, they'll be created by the
    //  session once the connection is established.
    if (options.immediate_connect) {

        //  Create a bi-directional pipe.
        object_t *parents [2] = {this, session};
        pipe_t *pipes [2] = {NULL, NULL};
        int hwms [2] = {options.sndhwm, options.rcvhwm};
        bool delays [2] = {options.delay_on_disconnect, options.delay_on_close};
        int rc = pipepair (parents, pipes, hwms, delays);
        errno_assert (rc == 0);

        //  Attach local end of the pipe to the socket object.
        attach_pipe (pipes [0], blob_t ());

        //  Attach remote end of the pipe to the session object later on.
        session->attach_pipe (pipes [1]);
    }

    //  Activate the session. Make it a child of this socket.
    launch_child (session);

    return 0;
}
Esempio n. 17
0
void zmq::mechanism_t::set_peer_identity (const void *id_ptr, size_t id_size)
{
    identity = blob_t (static_cast <const unsigned char*> (id_ptr), id_size);
}
Esempio n. 18
0
void zmq::connect_session_t::start_connecting (bool wait_)
{
    //  Choose I/O thread to run connecter in. Given that we are already
    //  running in an I/O thread, there must be at least one available.
    io_thread_t *io_thread = choose_io_thread (options.affinity);
    zmq_assert (io_thread);

    //  Create the connecter object.

    //  Both TCP and IPC transports are using the same infrastructure.
    if (protocol == "tcp" || protocol == "ipc") {

        zmq_connecter_t *connecter = new (std::nothrow) zmq_connecter_t (
            io_thread, this, options, protocol.c_str (), address.c_str (),
            wait_);
        alloc_assert (connecter);
        launch_child (connecter);
        return;
    }

#if defined ZMQ_HAVE_OPENPGM

    //  Both PGM and EPGM transports are using the same infrastructure.
    if (protocol == "pgm" || protocol == "epgm") {

        //  For EPGM transport with UDP encapsulation of PGM is used.
        bool udp_encapsulation = (protocol == "epgm");

        //  At this point we'll create message pipes to the session straight
        //  away. There's no point in delaying it as no concept of 'connect'
        //  exists with PGM anyway.
        if (options.type == ZMQ_PUB || options.type == ZMQ_XPUB) {

            //  PGM sender.
            pgm_sender_t *pgm_sender =  new (std::nothrow) pgm_sender_t (
                io_thread, options);
            alloc_assert (pgm_sender);

            int rc = pgm_sender->init (udp_encapsulation, address.c_str ());
            zmq_assert (rc == 0);

            send_attach (this, pgm_sender, blob_t ());
        }
        else if (options.type == ZMQ_SUB || options.type == ZMQ_XSUB) {

            //  PGM receiver.
            pgm_receiver_t *pgm_receiver =  new (std::nothrow) pgm_receiver_t (
                io_thread, options);
            alloc_assert (pgm_receiver);

            int rc = pgm_receiver->init (udp_encapsulation, address.c_str ());
            zmq_assert (rc == 0);

            send_attach (this, pgm_receiver, blob_t ());
        }
        else
            zmq_assert (false);

        return;
    }
#endif

    zmq_assert (false);
}
Esempio n. 19
0
int zmq::socket_base_t::connect (const char *addr_)
{
    if (unlikely (app_thread->is_terminated ())) {
        errno = ETERM;
        return -1;
    }

    //  Parse addr_ string.
    std::string addr_type;
    std::string addr_args;

    std::string addr (addr_);
    std::string::size_type pos = addr.find ("://");

    if (pos == std::string::npos) {
        errno = EINVAL;
        return -1;
    }

    addr_type = addr.substr (0, pos);
    addr_args = addr.substr (pos + 3);

    if (addr_type == "inproc") {

        //  TODO: inproc connect is specific with respect to creating pipes
        //  as there's no 'reconnect' functionality implemented. Once that
        //  is in place we should follow generic pipe creation algorithm.

        //  Find the peer socket.
        socket_base_t *peer = find_endpoint (addr_args.c_str ());
        if (!peer)
            return -1;

        pipe_t *in_pipe = NULL;
        pipe_t *out_pipe = NULL;

        //  Create inbound pipe, if required.
        if (options.requires_in) {
            in_pipe = new (std::nothrow) pipe_t (this, peer, options.hwm);
            zmq_assert (in_pipe);
        }

        //  Create outbound pipe, if required.
        if (options.requires_out) {
            out_pipe = new (std::nothrow) pipe_t (peer, this, options.hwm);
            zmq_assert (out_pipe);
        }

        //  Attach the pipes to this socket object.
        attach_pipes (in_pipe ? &in_pipe->reader : NULL,
            out_pipe ? &out_pipe->writer : NULL, blob_t ());

        //  Attach the pipes to the peer socket. Note that peer's seqnum
        //  was incremented in find_endpoint function. The callee is notified
        //  about the fact via the last parameter.
        send_bind (peer, out_pipe ? &out_pipe->reader : NULL,
            in_pipe ? &in_pipe->writer : NULL, options.identity, false);

        return 0;
    }

    //  Create unnamed session.
    io_thread_t *io_thread = choose_io_thread (options.affinity);
    session_t *session = new (std::nothrow) session_t (io_thread,
        this, options);
    zmq_assert (session);

    //  If 'immediate connect' feature is required, we'll created the pipes
    //  to the session straight away. Otherwise, they'll be created by the
    //  session once the connection is established.
    if (options.immediate_connect) {

        pipe_t *in_pipe = NULL;
        pipe_t *out_pipe = NULL;

        //  Create inbound pipe, if required.
        if (options.requires_in) {
            in_pipe = new (std::nothrow) pipe_t (this, session, options.hwm);
            zmq_assert (in_pipe);

        }

        //  Create outbound pipe, if required.
        if (options.requires_out) {
            out_pipe = new (std::nothrow) pipe_t (session, this, options.hwm);
            zmq_assert (out_pipe);
        }

        //  Attach the pipes to the socket object.
        attach_pipes (in_pipe ? &in_pipe->reader : NULL,
            out_pipe ? &out_pipe->writer : NULL, blob_t ());

        //  Attach the pipes to the session object.
        session->attach_pipes (out_pipe ? &out_pipe->reader : NULL,
            in_pipe ? &in_pipe->writer : NULL, blob_t ());
    }

    //  Activate the session.
    send_plug (session);
    send_own (this, session);

    if (addr_type == "tcp" || addr_type == "ipc") {

#if defined ZMQ_HAVE_WINDOWS || defined ZMQ_HAVE_OPENVMS
        //  Windows named pipes are not compatible with Winsock API.
        //  There's no UNIX domain socket implementation on OpenVMS.
        if (addr_type == "ipc") {
            errno = EPROTONOSUPPORT;
            return -1;
        }
#endif

        //  Create the connecter object. Supply it with the session name
        //  so that it can bind the new connection to the session once
        //  it is established.
        zmq_connecter_t *connecter = new (std::nothrow) zmq_connecter_t (
            choose_io_thread (options.affinity), this, options,
            session->get_ordinal (), false);
        zmq_assert (connecter);
        int rc = connecter->set_address (addr_type.c_str(), addr_args.c_str ());
        if (rc != 0) {
            delete connecter;
            return -1;
        }
        send_plug (connecter);
        send_own (this, connecter);

        return 0;
    }

#if defined ZMQ_HAVE_OPENPGM
    if (addr_type == "pgm" || addr_type == "epgm") {

        //  If the socket type requires bi-directional communication
        //  multicast is not an option (it is uni-directional).
        if (options.requires_in && options.requires_out) {
            errno = ENOCOMPATPROTO;
            return -1;
        }

        //  For epgm, pgm transport with UDP encapsulation is used.
        bool udp_encapsulation = (addr_type == "epgm");

        //  At this point we'll create message pipes to the session straight
        //  away. There's no point in delaying it as no concept of 'connect'
        //  exists with PGM anyway.
        if (options.requires_out) {

            //  PGM sender.
            pgm_sender_t *pgm_sender =  new (std::nothrow) pgm_sender_t (
                choose_io_thread (options.affinity), options);
            zmq_assert (pgm_sender);

            int rc = pgm_sender->init (udp_encapsulation, addr_args.c_str ());
            if (rc != 0) {
                delete pgm_sender;
                return -1;
            }

            send_attach (session, pgm_sender, blob_t ());
        }
        else if (options.requires_in) {

            //  PGM receiver.
            pgm_receiver_t *pgm_receiver =  new (std::nothrow) pgm_receiver_t (
                choose_io_thread (options.affinity), options);
            zmq_assert (pgm_receiver);

            int rc = pgm_receiver->init (udp_encapsulation, addr_args.c_str ());
            if (rc != 0) {
                delete pgm_receiver;
                return -1;
            }

            send_attach (session, pgm_receiver, blob_t ());
        }
        else
            zmq_assert (false);

        return 0;
    }
#endif

    //  Unknown protoco.
    errno = EPROTONOSUPPORT;
    return -1;
}
Esempio n. 20
0
void zmq::object_t::process_command (command_t &cmd_)
{
    switch (cmd_.type) {

    case command_t::revive:
        process_revive ();
        break;

    case command_t::stop:
        process_stop ();
        break;

    case command_t::plug:
        process_plug ();
        process_seqnum ();
        return;

    case command_t::own:
        process_own (cmd_.args.own.object);
        process_seqnum ();
        break;

    case command_t::attach:
        process_attach (cmd_.args.attach.engine,
            blob_t (cmd_.args.attach.peer_identity,
            cmd_.args.attach.peer_identity_size));
        process_seqnum ();
        break;

    case command_t::bind:
        process_bind (cmd_.args.bind.in_pipe, cmd_.args.bind.out_pipe,
            cmd_.args.bind.peer_identity ? blob_t (cmd_.args.bind.peer_identity,
            cmd_.args.bind.peer_identity_size) : blob_t ());
        process_seqnum ();
        break;

    case command_t::reader_info:
        process_reader_info (cmd_.args.reader_info.msgs_read);
        break;

    case command_t::pipe_term:
        process_pipe_term ();
        return;

    case command_t::pipe_term_ack:
        process_pipe_term_ack ();
        break;

    case command_t::term_req:
        process_term_req (cmd_.args.term_req.object);
        break;
    
    case command_t::term:
        process_term ();
        break;

    case command_t::term_ack:
        process_term_ack ();
        break;

    default:
        zmq_assert (false);
    }

    //  The assumption here is that each command is processed once only,
    //  so deallocating it after processing is all right.
    deallocate_command (&cmd_);
}
Esempio n. 21
0
void zmq::object_t::process_command (command_t &cmd_)
{
    switch (cmd_.type) {

    case command_t::activate_read:
        process_activate_read ();
        break;

    case command_t::activate_write:
        process_activate_write (cmd_.args.activate_write.msgs_read);
        break;

    case command_t::stop:
        process_stop ();
        break;

    case command_t::plug:
        process_plug ();
        process_seqnum ();
        break;

    case command_t::own:
        process_own (cmd_.args.own.object);
        process_seqnum ();
        break;

    case command_t::attach:
        process_attach (cmd_.args.attach.engine,
            cmd_.args.attach.peer_identity ?
            blob_t (cmd_.args.attach.peer_identity,
            cmd_.args.attach.peer_identity_size) : blob_t ());
        process_seqnum ();
        break;

    case command_t::bind:
        process_bind (cmd_.args.bind.pipe, cmd_.args.bind.peer_identity ?
            blob_t (cmd_.args.bind.peer_identity,
            cmd_.args.bind.peer_identity_size) : blob_t ());
        process_seqnum ();
        break;

    case command_t::hiccup:
        process_hiccup (cmd_.args.hiccup.pipe);
        break;

    case command_t::pipe_term:
        process_pipe_term ();
        break;

    case command_t::pipe_term_ack:
        process_pipe_term_ack ();
        break;

    case command_t::term_req:
        process_term_req (cmd_.args.term_req.object);
        break;
    
    case command_t::term:
        process_term (cmd_.args.term.linger);
        break;

    case command_t::term_ack:
        process_term_ack ();
        break;

    case command_t::reap:
        process_reap (cmd_.args.reap.socket);
        break;

    case command_t::reaped:
        process_reaped ();
        break;

    default:
        zmq_assert (false);
    }

    //  The assumption here is that each command is processed once only,
    //  so deallocating it after processing is all right.
    deallocate_command (&cmd_);
}