Example #1
0
zmq::server_t::~server_t ()
{    
    zmq_assert (outpipes.empty ());
}
Example #2
0
bool zmq::trie_t::rm (unsigned char *prefix_, size_t size_)
{
    //  TODO: Shouldn't an error be reported if the key does not exist?
    if (!size_) {
        if (!refcnt)
            return false;
        refcnt--;
        return refcnt == 0;
    }
    unsigned char c = *prefix_;
    if (!count || c < min || c >= min + count)
        return false;

    trie_t *next_node =
        count == 1 ? next.node : next.table [c - min];

    if (!next_node)
        return false;

    bool ret = next_node->rm (prefix_ + 1, size_ - 1);

    //  Prune redundant nodes
    if (next_node->is_redundant ()) {
        delete next_node;
        zmq_assert (count > 0);

        if (count == 1) {
            //  The just pruned node is was the only live node
            next.node = 0;
            count = 0;
            --live_nodes;
            zmq_assert (live_nodes == 0);
        }
        else {
            next.table [c - min] = 0;
            zmq_assert (live_nodes > 1);
            --live_nodes;

            //  Compact the table if possible
            if (live_nodes == 1) {
                //  We can switch to using the more compact single-node
                //  representation since the table only contains one live node
                trie_t *node = 0;
                //  Since we always compact the table the pruned node must
                //  either be the left-most or right-most ptr in the node
                //  table
                if (c == min) {
                    //  The pruned node is the left-most node ptr in the
                    //  node table => keep the right-most node
                    node = next.table [count - 1];
                    min += count - 1;
                }
                else
                if (c == min + count - 1) {
                    //  The pruned node is the right-most node ptr in the
                    //  node table => keep the left-most node
                    node = next.table [0];
                }
                zmq_assert (node);
                free (next.table);
                next.node = node;
                count = 1;
            }
            else
            if (c == min) {
                //  We can compact the table "from the left".
                //  Find the left-most non-null node ptr, which we'll use as
                //  our new min
                unsigned char new_min = min;
                for (unsigned short i = 1; i < count; ++i) {
                    if (next.table [i]) {
                        new_min = i + min;
                        break;
                    }
                }
                zmq_assert (new_min != min);

                trie_t **old_table = next.table;
                zmq_assert (new_min > min);
                zmq_assert (count > new_min - min);

                count = count - (new_min - min);
                next.table = (trie_t**) malloc (sizeof (trie_t*) * count);
                alloc_assert (next.table);

                memmove (next.table, old_table + (new_min - min),
                        sizeof (trie_t*) * count);
                free (old_table);

                min = new_min;
            }
            else
            if (c == min + count - 1) {
                //  We can compact the table "from the right".
                //  Find the right-most non-null node ptr, which we'll use to
                //  determine the new table size
                unsigned short new_count = count;
                for (unsigned short i = 1; i < count; ++i) {
                    if (next.table [count - 1 - i]) {
                        new_count = count - i;
                        break;
                    }
                }
                zmq_assert (new_count != count);
                count = new_count;

                trie_t **old_table = next.table;
                next.table = (trie_t**) malloc (sizeof (trie_t*) * count);
                alloc_assert (next.table);

                memmove (next.table, old_table, sizeof (trie_t*) * count);
                free (old_table);
            }
        }
    }
    return ret;
}
Example #3
0
int zmq::resolve_ip_interface (sockaddr_storage* addr_, socklen_t *addr_len_,
    char const *interface_)
{
    //  Find the ':' at end that separates NIC name from service.
    const char *delimiter = strrchr (interface_, ':');
    if (!delimiter) {
        errno = EINVAL;
        return -1;
    }

    //  Separate the name/port.
    std::string iface (interface_, delimiter - interface_);
    std::string service (delimiter + 1);

    //  Initialize the output parameter.
    memset (addr_, 0, sizeof (*addr_));

    //  Initialise IPv4-format family/port.
    sockaddr_in ip4_addr;
    memset (&ip4_addr, 0, sizeof (ip4_addr));
    ip4_addr.sin_family = AF_INET;
    ip4_addr.sin_port = htons ((uint16_t) atoi (service.c_str()));

    //  Initialize temporary output pointers with ip4_addr
    sockaddr *out_addr = (sockaddr *) &ip4_addr;
    size_t out_addrlen = sizeof (ip4_addr);

    //  0 is not a valid port.
    if (!ip4_addr.sin_port) {
        errno = EINVAL;
        return -1;
    }

    //  * resolves to INADDR_ANY.
    if (iface.compare("*") == 0) {
        ip4_addr.sin_addr.s_addr = htonl (INADDR_ANY);
        zmq_assert (out_addrlen <= sizeof (*addr_));
        memcpy (addr_, out_addr, out_addrlen);
        *addr_len_ = out_addrlen;
        return 0;
    }

    //  Try to resolve the string as a NIC name.
    int rc = resolve_nic_name (&ip4_addr.sin_addr, iface.c_str());
    if (rc != 0 && errno != ENODEV)
        return rc;
    if (rc == 0) {
        zmq_assert (out_addrlen <= sizeof (*addr_));
        memcpy (addr_, out_addr, out_addrlen);
        *addr_len_ = out_addrlen;
        return 0;
    }

    //  There's no such interface name. Assume literal address.
#if defined ZMQ_HAVE_OPENVMS && defined __ia64
    __addrinfo64 *res = NULL;
    __addrinfo64 req;
#else
    addrinfo *res = NULL;
    addrinfo req;
#endif
    memset (&req, 0, sizeof (req));

    //  We only support IPv4 addresses for now.
    req.ai_family = AF_INET;

    //  Arbitrary, not used in the output, but avoids duplicate results.
    req.ai_socktype = SOCK_STREAM;

    //  Restrict hostname/service to literals to avoid any DNS lookups or
    //  service-name irregularity due to indeterminate socktype.
    req.ai_flags = AI_PASSIVE | AI_NUMERICHOST | AI_NUMERICSERV;

    //  Resolve the literal address. Some of the error info is lost in case
    //  of error, however, there's no way to report EAI errors via errno.
    rc = getaddrinfo (iface.c_str(), service.c_str(), &req, &res);
    if (rc) {
        errno = ENODEV;
        return -1;
    }

    //  Use the first result.
    zmq_assert ((size_t) (res->ai_addrlen) <= sizeof (*addr_));
    memcpy (addr_, res->ai_addr, res->ai_addrlen);
    *addr_len_ = res->ai_addrlen;

    //  Cleanup getaddrinfo after copying the possibly referenced result.
    if (res)
        freeaddrinfo (res);

    return 0;
}
Example #4
0
void zmq::socket_base_t::xhiccuped (pipe_t *pipe_)
{
    zmq_assert (false);
}
Example #5
0
void zmq::socket_base_t::timer_event (int id_)
{
    zmq_assert (false);
}
Example #6
0
int zmq::router_t::xsend (msg_t *msg_, int flags_)
{
    //  If this is the first part of the message it's the ID of the
    //  peer to send the message to.
    if (!more_out) {
        zmq_assert (!current_out);

        int retval = 0;

        //  If we have malformed message (prefix with no subsequent message)
        //  then just silently ignore it.
        //  TODO: The connections should be killed instead.
        if (msg_->flags () & msg_t::more) {

            more_out = true;

            //  Find the pipe associated with the identity stored in the prefix.
            //  If there's no such pipe just silently ignore the message, unless
            //  fail_unreachable is set.
            blob_t identity ((unsigned char*) msg_->data (), msg_->size ());
            outpipes_t::iterator it = outpipes.find (identity);

            if (it != outpipes.end ()) {
                current_out = it->second.pipe;
                if (!current_out->check_write ()) {
                    it->second.active = false;
                    more_out = false;
                    current_out = NULL;
                }
            } else if(fail_unroutable) {
                more_out = false;
                errno = EHOSTUNREACH;
                retval = -1;
            }
        }

        int rc = msg_->close ();
        errno_assert (rc == 0);
        rc = msg_->init ();
        errno_assert (rc == 0);
        return retval;
    }

    //  Check whether this is the last part of the message.
    more_out = msg_->flags () & msg_t::more ? true : false;

    //  Push the message into the pipe. If there's no out pipe, just drop it.
    if (current_out) {
        bool ok = current_out->write (msg_);
        if (unlikely (!ok))
            current_out = NULL;
        else if (!more_out) {
            current_out->flush ();
            current_out = NULL;
        }
    }
    else {
        int rc = msg_->close ();
        errno_assert (rc == 0);
    }

    //  Detach the message from the data buffer.
    int rc = msg_->init ();
    errno_assert (rc == 0);

    return 0;
}
Example #7
0
zmq::router_t::~router_t ()
{
    zmq_assert (outpipes.empty ());
    prefetched_msg.close ();
}
Example #8
0
int zmq::curve_server_t::decode (msg_t *msg_)
{
    zmq_assert (state == connected);

    if (msg_->size () < 33) {
        //  Temporary support for security debugging
        puts ("CURVE I: invalid CURVE client, sent malformed command");
        errno = EPROTO;
        return -1;
    }

    const uint8_t *message = static_cast <uint8_t *> (msg_->data ());
    if (memcmp (message, "\x07MESSAGE", 8)) {
        //  Temporary support for security debugging
        puts ("CURVE I: invalid CURVE client, did not send MESSAGE");
        errno = EPROTO;
        return -1;
    }

    uint8_t message_nonce [crypto_box_NONCEBYTES];
    memcpy (message_nonce, "CurveZMQMESSAGEC", 16);
    memcpy (message_nonce + 16, message + 8, 8);
    uint64_t nonce = get_uint64(message + 8);
    if (nonce <= cn_peer_nonce) {
        errno = EPROTO;
        return -1;
    }
    cn_peer_nonce = nonce;

    const size_t clen = crypto_box_BOXZEROBYTES + msg_->size () - 16;

    uint8_t *message_plaintext = static_cast <uint8_t *> (malloc (clen));
    alloc_assert (message_plaintext);

    uint8_t *message_box = static_cast <uint8_t *> (malloc (clen));
    alloc_assert (message_box);

    memset (message_box, 0, crypto_box_BOXZEROBYTES);
    memcpy (message_box + crypto_box_BOXZEROBYTES,
            message + 16, msg_->size () - 16);

    int rc = crypto_box_open_afternm (message_plaintext, message_box,
                                      clen, message_nonce, cn_precom);
    if (rc == 0) {
        rc = msg_->close ();
        zmq_assert (rc == 0);

        rc = msg_->init_size (clen - 1 - crypto_box_ZEROBYTES);
        zmq_assert (rc == 0);

        const uint8_t flags = message_plaintext [crypto_box_ZEROBYTES];
        if (flags & 0x01)
            msg_->set_flags (msg_t::more);
        if (flags & 0x02)
            msg_->set_flags (msg_t::command);

        memcpy (msg_->data (),
                message_plaintext + crypto_box_ZEROBYTES + 1,
                msg_->size ());
    }
    else {
        //  Temporary support for security debugging
        puts ("CURVE I: connection key used for MESSAGE is wrong");
        errno = EPROTO;
    }
    free (message_plaintext);
    free (message_box);

    return rc;
}
Example #9
0
int zmq::curve_server_t::process_initiate (msg_t *msg_)
{
	puts("zmq::curve_server_t::process_initiate start");

	if (msg_->size() < 257) {
        //  Temporary support for security debugging
        puts ("CURVE I: client INITIATE is not correct size");
        errno = EPROTO;
        return -1;
    }

    const uint8_t *initiate = static_cast <uint8_t *> (msg_->data ());
    if (memcmp (initiate, "\x08INITIATE", 9)) {
        //  Temporary support for security debugging
        puts ("CURVE I: client INITIATE has invalid command name");
        errno = EPROTO;
        return -1;
    }

    uint8_t cookie_nonce [crypto_secretbox_NONCEBYTES];
    uint8_t cookie_plaintext [crypto_secretbox_ZEROBYTES + 64];
    uint8_t cookie_box [crypto_secretbox_BOXZEROBYTES + 80];

    //  Open Box [C' + s'](t)
    memset (cookie_box, 0, crypto_secretbox_BOXZEROBYTES);
    memcpy (cookie_box + crypto_secretbox_BOXZEROBYTES, initiate + 25, 80);

    memcpy (cookie_nonce, "COOKIE--", 8);
    memcpy (cookie_nonce + 8, initiate + 9, 16);

    int rc = crypto_secretbox_open (cookie_plaintext, cookie_box,
                                    sizeof cookie_box,
                                    cookie_nonce, cookie_key);
    if (rc != 0) {
        //  Temporary support for security debugging
        puts ("CURVE I: cannot open client INITIATE cookie");
        errno = EPROTO;
        return -1;
    }

    //  Check cookie plain text is as expected [C' + s']
    if (memcmp (cookie_plaintext + crypto_secretbox_ZEROBYTES, cn_client, 32)
    ||  memcmp (cookie_plaintext + crypto_secretbox_ZEROBYTES + 32, cn_secret, 32)) {
        //  Temporary support for security debugging
        puts ("CURVE I: client INITIATE cookie is not valid");
        errno = EPROTO;
        return -1;
    }

    const size_t clen = (msg_->size () - 113) + crypto_box_BOXZEROBYTES;

    uint8_t initiate_nonce [crypto_box_NONCEBYTES];
    uint8_t initiate_plaintext [crypto_box_ZEROBYTES + 128 + 256];
    uint8_t initiate_box [crypto_box_BOXZEROBYTES + 144 + 256];

    //  Open Box [C + vouch + metadata](C'->S')
    memset (initiate_box, 0, crypto_box_BOXZEROBYTES);
    memcpy (initiate_box + crypto_box_BOXZEROBYTES,
            initiate + 113, clen - crypto_box_BOXZEROBYTES);

    memcpy (initiate_nonce, "CurveZMQINITIATE", 16);
    memcpy (initiate_nonce + 16, initiate + 105, 8);
    cn_peer_nonce = get_uint64(initiate + 105);

    rc = crypto_box_open (initiate_plaintext, initiate_box,
                          clen, initiate_nonce, cn_client, cn_secret);
    if (rc != 0) {
        //  Temporary support for security debugging
        puts ("CURVE I: cannot open client INITIATE");
        errno = EPROTO;
        return -1;
    }

    const uint8_t *client_key = initiate_plaintext + crypto_box_ZEROBYTES;

    uint8_t vouch_nonce [crypto_box_NONCEBYTES];
    uint8_t vouch_plaintext [crypto_box_ZEROBYTES + 64];
    uint8_t vouch_box [crypto_box_BOXZEROBYTES + 80];

    //  Open Box Box [C',S](C->S') and check contents
    memset (vouch_box, 0, crypto_box_BOXZEROBYTES);
    memcpy (vouch_box + crypto_box_BOXZEROBYTES,
            initiate_plaintext + crypto_box_ZEROBYTES + 48, 80);

    memcpy (vouch_nonce, "VOUCH---", 8);
    memcpy (vouch_nonce + 8,
            initiate_plaintext + crypto_box_ZEROBYTES + 32, 16);

    rc = crypto_box_open (vouch_plaintext, vouch_box,
                          sizeof vouch_box,
                          vouch_nonce, client_key, cn_secret);
    if (rc != 0) {
        //  Temporary support for security debugging
        puts ("CURVE I: cannot open client INITIATE vouch");
        errno = EPROTO;
        return -1;
    }

    //  What we decrypted must be the client's short-term public key
    if (memcmp (vouch_plaintext + crypto_box_ZEROBYTES, cn_client, 32)) {
        //  Temporary support for security debugging
        puts ("CURVE I: invalid handshake from client (public key)");
        errno = EPROTO;
        return -1;
    }

    //  Precompute connection secret from client key
    rc = crypto_box_beforenm (cn_precom, cn_client, cn_secret);
    zmq_assert (rc == 0);

	puts("zmq::curve_server_t::process_initiate before zap_connect ");

	//  Use ZAP protocol (RFC 27) to authenticate the user.
    rc = session->zap_connect ();
    if (rc == 0) {
        send_zap_request (client_key);
        rc = receive_and_process_zap_reply ();
        if (rc == 0)
            state = status_code == "200"
                ? send_ready
                : send_error;
        else
        if (errno == EAGAIN)
            state = expect_zap_reply;
        else
            return -1;
    }
    else
        state = send_ready;

	puts("zmq::curve_server_t::process_initiate end");

    return parse_metadata (initiate_plaintext + crypto_box_ZEROBYTES + 128,
                           clen - crypto_box_ZEROBYTES - 128);
}
zmq::socks_connecter_t::~socks_connecter_t ()
{
    zmq_assert (s == retired_fd);
    LIBZMQ_DELETE(proxy_addr);
}
Example #11
0
void zmq::devpoll_t::devpoll_ctl (fd_t fd_, short events_)
{
    struct pollfd pfd = {fd_, events_, 0};
    ssize_t rc = write (devpoll_fd, &pfd, sizeof pfd);
    zmq_assert (rc == sizeof pfd);
}
int zmq::socks_connecter_t::connect_to_proxy ()
{
    zmq_assert (s == retired_fd);

    //  Resolve the address
    LIBZMQ_DELETE(proxy_addr->resolved.tcp_addr);
    proxy_addr->resolved.tcp_addr = new (std::nothrow) tcp_address_t ();
    alloc_assert (proxy_addr->resolved.tcp_addr);

    int rc = proxy_addr->resolved.tcp_addr->resolve (
        proxy_addr->address.c_str (), false, options.ipv6);
    if (rc != 0) {
        LIBZMQ_DELETE(proxy_addr->resolved.tcp_addr);
        return -1;
    }
    zmq_assert (proxy_addr->resolved.tcp_addr != NULL);
    const tcp_address_t *tcp_addr = proxy_addr->resolved.tcp_addr;

    //  Create the socket.
    s = open_socket (tcp_addr->family (), SOCK_STREAM, IPPROTO_TCP);
#ifdef ZMQ_HAVE_WINDOWS
    if (s == INVALID_SOCKET)
        return -1;
#else
    if (s == -1)
        return -1;
#endif

    //  On some systems, IPv4 mapping in IPv6 sockets is disabled by default.
    //  Switch it on in such cases.
    if (tcp_addr->family () == AF_INET6)
        enable_ipv4_mapping (s);

    // Set the IP Type-Of-Service priority for this socket
    if (options.tos != 0)
        set_ip_type_of_service (s, options.tos);

    // Set the socket to non-blocking mode so that we get async connect().
    unblock_socket (s);

    //  Set the socket buffer limits for the underlying socket.
    if (options.sndbuf >= 0)
        set_tcp_send_buffer (s, options.sndbuf);
    if (options.rcvbuf >= 0)
        set_tcp_receive_buffer (s, options.rcvbuf);

    // Set the IP Type-Of-Service for the underlying socket
    if (options.tos != 0)
        set_ip_type_of_service (s, options.tos);

    // Set a source address for conversations
    if (tcp_addr->has_src_addr ()) {
        rc = ::bind (s, tcp_addr->src_addr (), tcp_addr->src_addrlen ());
        if (rc == -1) {
            close ();
            return -1;
        }
    }

    //  Connect to the remote peer.
    rc = ::connect (s, tcp_addr->addr (), tcp_addr->addrlen ());

    //  Connect was successful immediately.
    if (rc == 0)
        return 0;

    //  Translate error codes indicating asynchronous connect has been
    //  launched to a uniform EINPROGRESS.
#ifdef ZMQ_HAVE_WINDOWS
    const int last_error = WSAGetLastError();
    if (last_error == WSAEINPROGRESS || last_error == WSAEWOULDBLOCK)
        errno = EINPROGRESS;
    else {
        errno = wsa_error_to_errno (last_error);
        close ();
    }
#else
    if (errno == EINTR)
        errno = EINPROGRESS;
#endif
    return -1;
}
void zmq::socks_connecter_t::timer_event (int id_)
{
    zmq_assert (status == waiting_for_reconnect_time);
    zmq_assert (id_ == reconnect_timer_id);
    initiate_connect ();
}
void zmq::socks_connecter_t::in_event ()
{
    zmq_assert (status != unplugged
             && status != waiting_for_reconnect_time);

    if (status == waiting_for_choice) {
        const 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 ();
             const int 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) {
        const 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 ();
            const int rc = process_server_response (response);
            if (rc == -1)
                error ();
            else {
                //  Remember our fd for ZMQ_SRCFD in messages
                socket->set_fd (s);

                //  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 ();
}
Example #15
0
int zmq::options_t::getsockopt (int option_, void *optval_, size_t *optvallen_) const
{
    bool is_int = (*optvallen_ == sizeof (int));
    int *value = (int *) optval_;
#if defined (ZMQ_ACT_MILITANT)
    bool malformed = true;          //  Did caller pass a bad option value?
#endif

    switch (option_) {
    case ZMQ_SNDHWM:
        if (is_int) {
            *value = sndhwm;
            return 0;
        }
        break;

    case ZMQ_RCVHWM:
        if (is_int) {
            *value = rcvhwm;
            return 0;
        }
        break;

    case ZMQ_AFFINITY:
        if (*optvallen_ == sizeof (uint64_t)) {
            *((uint64_t *) optval_) = affinity;
            return 0;
        }
        break;

    case ZMQ_IDENTITY:
        if (*optvallen_ >= identity_size) {
            memcpy (optval_, identity, identity_size);
            *optvallen_ = identity_size;
            return 0;
        }
        break;

    case ZMQ_RATE:
        if (is_int) {
            *value = rate;
            return 0;
        }
        break;

    case ZMQ_RECOVERY_IVL:
        if (is_int) {
            *value = recovery_ivl;
            return 0;
        }
        break;

    case ZMQ_SNDBUF:
        if (is_int) {
            *value = sndbuf;
            return 0;
        }
        break;

    case ZMQ_RCVBUF:
        if (is_int) {
            *value = rcvbuf;
            return 0;
        }
        break;

    case ZMQ_TOS:
        if (is_int) {
            *value = tos;
            return 0;
        }
        break;

    case ZMQ_TYPE:
        if (is_int) {
            *value = type;
            return 0;
        }
        break;

    case ZMQ_LINGER:
        if (is_int) {
            *value = linger;
            return 0;
        }
        break;

    case ZMQ_CONNECT_TIMEOUT:
        if (is_int) {
            *value = connect_timeout;
            return 0;
        }
        break;

    case ZMQ_TCP_MAXRT:
        if (is_int) {
            *value = tcp_maxrt;
            return 0;
        }
        break;

    case ZMQ_RECONNECT_IVL:
        if (is_int) {
            *value = reconnect_ivl;
            return 0;
        }
        break;

    case ZMQ_RECONNECT_IVL_MAX:
        if (is_int) {
            *value = reconnect_ivl_max;
            return 0;
        }
        break;

    case ZMQ_BACKLOG:
        if (is_int) {
            *value = backlog;
            return 0;
        }
        break;

    case ZMQ_MAXMSGSIZE:
        if (*optvallen_ == sizeof (int64_t)) {
            *((int64_t *) optval_) = maxmsgsize;
            *optvallen_ = sizeof (int64_t);
            return 0;
        }
        break;

    case ZMQ_MULTICAST_HOPS:
        if (is_int) {
            *value = multicast_hops;
            return 0;
        }
        break;

    case ZMQ_MULTICAST_MAXTPDU:
        if (is_int) {
            *value = multicast_maxtpdu;
            return 0;
        }
        break;

    case ZMQ_RCVTIMEO:
        if (is_int) {
            *value = rcvtimeo;
            return 0;
        }
        break;

    case ZMQ_SNDTIMEO:
        if (is_int) {
            *value = sndtimeo;
            return 0;
        }
        break;

    case ZMQ_IPV4ONLY:
        if (is_int) {
            *value = 1 - ipv6;
            return 0;
        }
        break;

    case ZMQ_IPV6:
        if (is_int) {
            *value = ipv6;
            return 0;
        }
        break;

    case ZMQ_IMMEDIATE:
        if (is_int) {
            *value = immediate;
            return 0;
        }
        break;

    case ZMQ_SOCKS_PROXY:
        if (*optvallen_ >= socks_proxy_address.size () + 1) {
            memcpy (optval_, socks_proxy_address.c_str (), socks_proxy_address.size () + 1);
            *optvallen_ = socks_proxy_address.size () + 1;
            return 0;
        }
        break;

    case ZMQ_TCP_KEEPALIVE:
        if (is_int) {
            *value = tcp_keepalive;
            return 0;
        }
        break;

    case ZMQ_TCP_KEEPALIVE_CNT:
        if (is_int) {
            *value = tcp_keepalive_cnt;
            return 0;
        }
        break;

    case ZMQ_TCP_KEEPALIVE_IDLE:
        if (is_int) {
            *value = tcp_keepalive_idle;
            return 0;
        }
        break;

    case ZMQ_TCP_KEEPALIVE_INTVL:
        if (is_int) {
            *value = tcp_keepalive_intvl;
            return 0;
        }
        break;

    case ZMQ_MECHANISM:
        if (is_int) {
            *value = mechanism;
            return 0;
        }
        break;

    case ZMQ_PLAIN_SERVER:
        if (is_int) {
            *value = as_server && mechanism == ZMQ_PLAIN;
            return 0;
        }
        break;

    case ZMQ_PLAIN_USERNAME:
        if (*optvallen_ >= plain_username.size () + 1) {
            memcpy (optval_, plain_username.c_str (), plain_username.size () + 1);
            *optvallen_ = plain_username.size () + 1;
            return 0;
        }
        break;

    case ZMQ_PLAIN_PASSWORD:
        if (*optvallen_ >= plain_password.size () + 1) {
            memcpy (optval_, plain_password.c_str (), plain_password.size () + 1);
            *optvallen_ = plain_password.size () + 1;
            return 0;
        }
        break;

    case ZMQ_ZAP_DOMAIN:
        if (*optvallen_ >= zap_domain.size () + 1) {
            memcpy (optval_, zap_domain.c_str (), zap_domain.size () + 1);
            *optvallen_ = zap_domain.size () + 1;
            return 0;
        }
        break;

        //  If curve encryption isn't built, these options provoke EINVAL
#ifdef ZMQ_HAVE_CURVE
    case ZMQ_CURVE_SERVER:
        if (is_int) {
            *value = as_server && mechanism == ZMQ_CURVE;
            return 0;
        }
        break;

    case ZMQ_CURVE_PUBLICKEY:
        if (*optvallen_ == CURVE_KEYSIZE) {
            memcpy (optval_, curve_public_key, CURVE_KEYSIZE);
            return 0;
        }
        else if (*optvallen_ == CURVE_KEYSIZE_Z85 + 1) {
            zmq_z85_encode ((char *) optval_, curve_public_key, CURVE_KEYSIZE);
            return 0;
        }
        break;

    case ZMQ_CURVE_SECRETKEY:
        if (*optvallen_ == CURVE_KEYSIZE) {
            memcpy (optval_, curve_secret_key, CURVE_KEYSIZE);
            return 0;
        }
        else if (*optvallen_ == CURVE_KEYSIZE_Z85 + 1) {
            zmq_z85_encode ((char *) optval_, curve_secret_key, CURVE_KEYSIZE);
            return 0;
        }
        break;

    case ZMQ_CURVE_SERVERKEY:
        if (*optvallen_ == CURVE_KEYSIZE) {
            memcpy (optval_, curve_server_key, CURVE_KEYSIZE);
            return 0;
        }
        else if (*optvallen_ == CURVE_KEYSIZE_Z85 + 1) {
            zmq_z85_encode ((char *) optval_, curve_server_key, CURVE_KEYSIZE);
            return 0;
        }
        break;
#endif

    case ZMQ_CONFLATE:
        if (is_int) {
            *value = conflate;
            return 0;
        }
        break;

        //  If libgssapi isn't installed, these options provoke EINVAL
#ifdef HAVE_LIBGSSAPI_KRB5
    case ZMQ_GSSAPI_SERVER:
        if (is_int) {
            *value = as_server && mechanism == ZMQ_GSSAPI;
            return 0;
        }
        break;

    case ZMQ_GSSAPI_PRINCIPAL:
        if (*optvallen_ >= gss_principal.size () + 1) {
            memcpy (optval_, gss_principal.c_str (), gss_principal.size () + 1);
            *optvallen_ = gss_principal.size () + 1;
            return 0;
        }
        break;

    case ZMQ_GSSAPI_SERVICE_PRINCIPAL:
        if (*optvallen_ >= gss_service_principal.size () + 1) {
            memcpy (optval_, gss_service_principal.c_str (), gss_service_principal.size () + 1);
            *optvallen_ = gss_service_principal.size () + 1;
            return 0;
        }
        break;

    case ZMQ_GSSAPI_PLAINTEXT:
        if (is_int) {
            *value = gss_plaintext;
            return 0;
        }
        break;
#endif

    case ZMQ_HANDSHAKE_IVL:
        if (is_int) {
            *value = handshake_ivl;
            return 0;
        }
        break;

    case ZMQ_INVERT_MATCHING:
        if (is_int) {
            *value = invert_matching;
            return 0;
        }
        break;

    case ZMQ_HEARTBEAT_IVL:
        if (is_int) {
            *value = heartbeat_interval;
            return 0;
        }
        break;

    case ZMQ_HEARTBEAT_TTL:
        if (is_int) {
            // Convert the internal deciseconds value to milliseconds
            *value = heartbeat_ttl * 100;
            return 0;
        }
        break;

    case ZMQ_HEARTBEAT_TIMEOUT:
        if (is_int) {
            *value = heartbeat_timeout;
            return 0;
        }
        break;

    case ZMQ_USE_FD:
        if (is_int) {
            *value = use_fd;
            return 0;
        }
        break;

    default:
#if defined (ZMQ_ACT_MILITANT)
        malformed = false;
#endif
        break;
    }
#if defined (ZMQ_ACT_MILITANT)
    if (malformed)
        zmq_assert (false);
#endif
    errno = EINVAL;
    return -1;
}
Example #16
0
int zmq_poll (zmq_pollitem_t *items_, int nitems_, long timeout_)
{
#if defined ZMQ_HAVE_LINUX || defined ZMQ_HAVE_FREEBSD ||\
    defined ZMQ_HAVE_OPENBSD || defined ZMQ_HAVE_SOLARIS ||\
    defined ZMQ_HAVE_OSX || defined ZMQ_HAVE_QNXNTO ||\
    defined ZMQ_HAVE_HPUX || defined ZMQ_HAVE_AIX ||\
    defined ZMQ_HAVE_NETBSD

    pollfd *pollfds = (pollfd*) malloc (nitems_ * sizeof (pollfd));
    zmq_assert (pollfds);
    int npollfds = 0;
    int nsockets = 0;

    zmq::app_thread_t *app_thread = NULL;

    for (int i = 0; i != nitems_; i++) {

        //  0MQ sockets.
        if (items_ [i].socket) {

            //  Get the app_thread the socket is living in. If there are two
            //  sockets in the same pollset with different app threads, fail.
            zmq::socket_base_t *s = (zmq::socket_base_t*) items_ [i].socket;
            if (app_thread) {
                if (app_thread != s->get_thread ()) {
                    free (pollfds);
                    errno = EFAULT;
                    return -1;
                }
            }
            else
                app_thread = s->get_thread ();

            nsockets++;
            continue;
        }

        //  Raw file descriptors.
        pollfds [npollfds].fd = items_ [i].fd;
        pollfds [npollfds].events =
            (items_ [i].events & ZMQ_POLLIN ? POLLIN : 0) |
            (items_ [i].events & ZMQ_POLLOUT ? POLLOUT : 0);
        npollfds++;
    }

    //  If there's at least one 0MQ socket in the pollset we have to poll
    //  for 0MQ commands. If ZMQ_POLL was not set, fail.
    if (nsockets) {
        pollfds [npollfds].fd = app_thread->get_signaler ()->get_fd ();
        if (pollfds [npollfds].fd == zmq::retired_fd) {
            free (pollfds);
            errno = ENOTSUP;
            return -1;
        }
        pollfds [npollfds].events = POLLIN;
        npollfds++;
    }

    //  First iteration just check for events, don't block. Waiting would
    //  prevent exiting on any events that may already been signaled on
    //  0MQ sockets.
    int rc = poll (pollfds, npollfds, 0);
    if (rc == -1 && errno == EINTR && timeout_ >= 0) {
        free (pollfds);
        return 0;
    }
    errno_assert (rc >= 0 || (rc == -1 && errno == EINTR));

    int timeout = timeout_ > 0 ? timeout_ / 1000 : -1;
    int nevents = 0;

    while (true) {

        //  Process 0MQ commands if needed.
        if (nsockets && pollfds [npollfds -1].revents & POLLIN)
            app_thread->process_commands (false, false);

        //  Check for the events.
        int pollfd_pos = 0;
        for (int i = 0; i != nitems_; i++) {

            //  If the poll item is a raw file descriptor, simply convert
            //  the events to zmq_pollitem_t-style format.
            if (!items_ [i].socket) {
                items_ [i].revents = 0;
                if (pollfds [pollfd_pos].revents & POLLIN)
                    items_ [i].revents |= ZMQ_POLLIN;
                if (pollfds [pollfd_pos].revents & POLLOUT)
                    items_ [i].revents |= ZMQ_POLLOUT;
                if (pollfds [pollfd_pos].revents & ~(POLLIN | POLLOUT))
                    items_ [i].revents |= ZMQ_POLLERR;

                if (items_ [i].revents)
                    nevents++;
                pollfd_pos++;
                continue;
            }

            //  The poll item is a 0MQ socket.
            zmq::socket_base_t *s = (zmq::socket_base_t*) items_ [i].socket;
            items_ [i].revents = 0;
            if ((items_ [i].events & ZMQ_POLLOUT) && s->has_out ())
                items_ [i].revents |= ZMQ_POLLOUT;
            if ((items_ [i].events & ZMQ_POLLIN) && s->has_in ())
                items_ [i].revents |= ZMQ_POLLIN;
            if (items_ [i].revents)
                nevents++;
        }

        //  If there's at least one event, or if we are asked not to block,
        //  return immediately.
        if (nevents || !timeout_)
            break;

        //  Wait for events. Ignore interrupts if there's infinite timeout.
        while (true) {
            rc = poll (pollfds, npollfds, timeout);
            if (rc == -1 && errno == EINTR) {
                if (timeout_ < 0)
                    continue;
                else {
                    rc = 0;
                    break;
                }
            }
            errno_assert (rc >= 0);
            break;
        }
        
        //  If timeout was hit with no events signaled, return zero.
        if (rc == 0)
            break;

        //  If timeout was already applied, we don't want to poll anymore.
        //  Setting timeout to zero will cause termination of the function
        //  once the events we've got are processed.
        if (timeout > 0)
            timeout = 0;
    }

    free (pollfds);
    return nevents;

#elif defined ZMQ_HAVE_WINDOWS || defined ZMQ_HAVE_OPENVMS

    fd_set pollset_in;
    FD_ZERO (&pollset_in);
    fd_set pollset_out;
    FD_ZERO (&pollset_out);
    fd_set pollset_err;
    FD_ZERO (&pollset_err);

    zmq::app_thread_t *app_thread = NULL;
    int nsockets = 0;
    zmq::fd_t maxfd = zmq::retired_fd;
    zmq::fd_t notify_fd = zmq::retired_fd;

    for (int i = 0; i != nitems_; i++) {

        //  0MQ sockets.
        if (items_ [i].socket) {

            //  Get the app_thread the socket is living in. If there are two
            //  sockets in the same pollset with different app threads, fail.
            zmq::socket_base_t *s = (zmq::socket_base_t*) items_ [i].socket;
            if (app_thread) {
                if (app_thread != s->get_thread ()) {
                    errno = EFAULT;
                    return -1;
                }
            }
            else
                app_thread = s->get_thread ();

            nsockets++;
            continue;
        }

        //  Raw file descriptors.
        if (items_ [i].events & ZMQ_POLLIN)
            FD_SET (items_ [i].fd, &pollset_in);
        if (items_ [i].events & ZMQ_POLLOUT)
            FD_SET (items_ [i].fd, &pollset_out);
        if (items_ [i].events & ZMQ_POLLERR)
            FD_SET (items_ [i].fd, &pollset_err);
        if (maxfd == zmq::retired_fd || maxfd < items_ [i].fd)
            maxfd = items_ [i].fd;
    }

    //  If there's at least one 0MQ socket in the pollset we have to poll
    //  for 0MQ commands. If ZMQ_POLL was not set, fail.
    if (nsockets) {
        notify_fd = app_thread->get_signaler ()->get_fd ();
        if (notify_fd == zmq::retired_fd) {
            errno = ENOTSUP;
            return -1;
        }
        FD_SET (notify_fd, &pollset_in);
        if (maxfd == zmq::retired_fd || maxfd < notify_fd)
            maxfd = notify_fd;
    }

    bool block = (timeout_ < 0);
    timeval timeout = {timeout_ / 1000000, timeout_ % 1000000};
    timeval zero_timeout = {0, 0};
    int nevents = 0;

    //  First iteration just check for events, don't block. Waiting would
    //  prevent exiting on any events that may already been signaled on
    //  0MQ sockets.
    fd_set inset, outset, errset;
    memcpy (&inset, &pollset_in, sizeof (fd_set));
    memcpy (&outset, &pollset_out, sizeof (fd_set));
    memcpy (&errset, &pollset_err, sizeof (fd_set));
    int rc = select (maxfd, &inset, &outset, &errset, &zero_timeout);
#if defined ZMQ_HAVE_WINDOWS
    wsa_assert (rc != SOCKET_ERROR);
#else
    if (rc == -1 && errno == EINTR && timeout_ >= 0)
        return 0;
    errno_assert (rc >= 0 || (rc == -1 && errno == EINTR));
#endif

    while (true) {

        //  Process 0MQ commands if needed.
        if (nsockets && FD_ISSET (notify_fd, &inset))
            app_thread->process_commands (false, false);

        //  Check for the events.
        for (int i = 0; i != nitems_; i++) {

            //  If the poll item is a raw file descriptor, simply convert
            //  the events to zmq_pollitem_t-style format.
            if (!items_ [i].socket) {
                items_ [i].revents = 0;
                if (FD_ISSET (items_ [i].fd, &inset))
                    items_ [i].revents |= ZMQ_POLLIN;
                if (FD_ISSET (items_ [i].fd, &outset))
                    items_ [i].revents |= ZMQ_POLLOUT;
                if (FD_ISSET (items_ [i].fd, &errset))
                    items_ [i].revents |= ZMQ_POLLERR;
                if (items_ [i].revents)
                    nevents++;
                continue;
            }

            //  The poll item is a 0MQ socket.
            zmq::socket_base_t *s = (zmq::socket_base_t*) items_ [i].socket;
            items_ [i].revents = 0;
            if ((items_ [i].events & ZMQ_POLLOUT) && s->has_out ())
                items_ [i].revents |= ZMQ_POLLOUT;
            if ((items_ [i].events & ZMQ_POLLIN) && s->has_in ())
                items_ [i].revents |= ZMQ_POLLIN;
            if (items_ [i].revents)
                nevents++;
        }

        //  If there's at least one event, or if we are asked not to block,
        //  return immediately.
        if (nevents || (timeout.tv_sec == 0 && timeout.tv_usec == 0))
            break;

        //  Wait for events. Ignore interrupts if there's infinite timeout.
        while (true) {
            memcpy (&inset, &pollset_in, sizeof (fd_set));
            memcpy (&outset, &pollset_out, sizeof (fd_set));
            memcpy (&errset, &pollset_err, sizeof (fd_set));
            int rc = select (maxfd, &inset, &outset, &errset,
                block ? NULL : &timeout);
#if defined ZMQ_HAVE_WINDOWS
            wsa_assert (rc != SOCKET_ERROR);
#else
            if (rc == -1 && errno == EINTR) {
                if (timeout_ < 0)
                    continue;
                else {
                    rc = 0;
                    break;
                }
            }
            errno_assert (rc >= 0);
#endif
            break;
        }
        
        //  If timeout was hit with no events signaled, return zero.
        if (rc == 0)
            break;

        //  If timeout was already applied, we don't want to poll anymore.
        //  Setting timeout to zero will cause termination of the function
        //  once the events we've got are processed.
        if (!block)
            timeout = zero_timeout;
    }

    return nevents;

#else
    errno = ENOTSUP;
    return -1;
#endif
}
Example #17
0
int zmq::options_t::setsockopt (int option_, const void *optval_,
                                size_t optvallen_)
{
    bool is_int = (optvallen_ == sizeof (int));
    int value = 0;
    if (is_int) memcpy(&value, optval_, sizeof (int));
#if defined (ZMQ_ACT_MILITANT)
    bool malformed = true;          //  Did caller pass a bad option value?
#endif

    switch (option_) {
    case ZMQ_SNDHWM:
        if (is_int && value >= 0) {
            sndhwm = value;
            return 0;
        }
        break;

    case ZMQ_RCVHWM:
        if (is_int && value >= 0) {
            rcvhwm = value;
            return 0;
        }
        break;

    case ZMQ_AFFINITY:
        if (optvallen_ == sizeof (uint64_t)) {
            affinity = *((uint64_t*) optval_);
            return 0;
        }
        break;

    case ZMQ_IDENTITY:
        //  Identity is any binary string from 1 to 255 octets
        if (optvallen_ > 0 && optvallen_ < 256) {
            identity_size = (unsigned char) optvallen_;
            memcpy (identity, optval_, identity_size);
            return 0;
        }
        break;

    case ZMQ_RATE:
        if (is_int && value > 0) {
            rate = value;
            return 0;
        }
        break;

    case ZMQ_RECOVERY_IVL:
        if (is_int && value >= 0) {
            recovery_ivl = value;
            return 0;
        }
        break;

    case ZMQ_SNDBUF:
        if (is_int && value >= 0) {
            sndbuf = value;
            return 0;
        }
        break;

    case ZMQ_RCVBUF:
        if (is_int && value >= 0) {
            rcvbuf = value;
            return 0;
        }
        break;

    case ZMQ_TOS:
        if (is_int && value >= 0) {
            tos = value;
            return 0;
        }
        break;

    case ZMQ_LINGER:
        if (is_int && value >= -1) {
            linger = value;
            return 0;
        }
        break;

    case ZMQ_CONNECT_TIMEOUT:
        if (is_int && value >= 0) {
            connect_timeout = value;
            return 0;
        }
        break;

    case ZMQ_TCP_MAXRT:
        if (is_int && value >= 0) {
            tcp_maxrt = value;
            return 0;
        }
        break;

    case ZMQ_RECONNECT_IVL:
        if (is_int && value >= -1) {
            reconnect_ivl = value;
            return 0;
        }
        break;

    case ZMQ_RECONNECT_IVL_MAX:
        if (is_int && value >= 0) {
            reconnect_ivl_max = value;
            return 0;
        }
        break;

    case ZMQ_BACKLOG:
        if (is_int && value >= 0) {
            backlog = value;
            return 0;
        }
        break;

    case ZMQ_MAXMSGSIZE:
        if (optvallen_ == sizeof (int64_t)) {
            maxmsgsize = *((int64_t *) optval_);
            return 0;
        }
        break;

    case ZMQ_MULTICAST_HOPS:
        if (is_int && value > 0) {
            multicast_hops = value;
            return 0;
        }
        break;

    case ZMQ_MULTICAST_MAXTPDU:
        if (is_int && value > 0) {
            multicast_maxtpdu = value;
            return 0;
        }
        break;

    case ZMQ_RCVTIMEO:
        if (is_int && value >= -1) {
            rcvtimeo = value;
            return 0;
        }
        break;

    case ZMQ_SNDTIMEO:
        if (is_int && value >= -1) {
            sndtimeo = value;
            return 0;
        }
        break;

    /*  Deprecated in favor of ZMQ_IPV6  */
    case ZMQ_IPV4ONLY:
        if (is_int && (value == 0 || value == 1)) {
            ipv6 = (value == 0);
            return 0;
        }
        break;

    /*  To replace the somewhat surprising IPV4ONLY */
    case ZMQ_IPV6:
        if (is_int && (value == 0 || value == 1)) {
            ipv6 = (value != 0);
            return 0;
        }
        break;

    case ZMQ_SOCKS_PROXY:
        if (optval_ == NULL && optvallen_ == 0) {
            socks_proxy_address.clear ();
            return 0;
        }
        else if (optval_ != NULL && optvallen_ > 0 ) {
            socks_proxy_address =
                std::string ((const char *) optval_, optvallen_);
            return 0;
        }
        break;

    case ZMQ_TCP_KEEPALIVE:
        if (is_int && (value == -1 || value == 0 || value == 1)) {
            tcp_keepalive = value;
            return 0;
        }
        break;

    case ZMQ_TCP_KEEPALIVE_CNT:
        if (is_int && (value == -1 || value >= 0)) {
            tcp_keepalive_cnt = value;
            return 0;
        }
        break;

    case ZMQ_TCP_KEEPALIVE_IDLE:
        if (is_int && (value == -1 || value >= 0)) {
            tcp_keepalive_idle = value;
            return 0;
        }
        break;

    case ZMQ_TCP_KEEPALIVE_INTVL:
        if (is_int && (value == -1 || value >= 0)) {
            tcp_keepalive_intvl = value;
            return 0;
        }
        break;

    case ZMQ_IMMEDIATE:
        if (is_int && (value == 0 || value == 1)) {
            immediate = value;
            return 0;
        }
        break;

    case ZMQ_TCP_ACCEPT_FILTER:
        if (optvallen_ == 0 && optval_ == NULL) {
            tcp_accept_filters.clear ();
            return 0;
        }
        else if (optvallen_ > 0 && optvallen_ < 256 && optval_ != NULL && *((const char*) optval_) != 0) {
            std::string filter_str ((const char *) optval_, optvallen_);
            tcp_address_mask_t mask;
            int rc = mask.resolve (filter_str.c_str (), ipv6);
            if (rc == 0) {
                tcp_accept_filters.push_back (mask);
                return 0;
            }
        }
        break;

#if defined ZMQ_HAVE_SO_PEERCRED || defined ZMQ_HAVE_LOCAL_PEERCRED
    case ZMQ_IPC_FILTER_UID:
        if (optvallen_ == 0 && optval_ == NULL) {
            ipc_uid_accept_filters.clear ();
            return 0;
        }
        else if (optvallen_ == sizeof (uid_t) && optval_ != NULL) {
            ipc_uid_accept_filters.insert (*((uid_t *) optval_));
            return 0;
        }
        break;

    case ZMQ_IPC_FILTER_GID:
        if (optvallen_ == 0 && optval_ == NULL) {
            ipc_gid_accept_filters.clear ();
            return 0;
        }
        else if (optvallen_ == sizeof (gid_t) && optval_ != NULL) {
            ipc_gid_accept_filters.insert (*((gid_t *) optval_));
            return 0;
        }
        break;
#endif

#if defined ZMQ_HAVE_SO_PEERCRED
    case ZMQ_IPC_FILTER_PID:
        if (optvallen_ == 0 && optval_ == NULL) {
            ipc_pid_accept_filters.clear ();
            return 0;
        }
        else if (optvallen_ == sizeof (pid_t) && optval_ != NULL) {
            ipc_pid_accept_filters.insert (*((pid_t *) optval_));
            return 0;
        }
        break;
#endif

    case ZMQ_PLAIN_SERVER:
        if (is_int && (value == 0 || value == 1)) {
            as_server = value;
            mechanism = value? ZMQ_PLAIN: ZMQ_NULL;
            return 0;
        }
        break;

    case ZMQ_PLAIN_USERNAME:
        if (optvallen_ == 0 && optval_ == NULL) {
            mechanism = ZMQ_NULL;
            return 0;
        }
        else if (optvallen_ > 0 && optvallen_ < 256 && optval_ != NULL) {
            plain_username.assign ((const char *) optval_, optvallen_);
            as_server = 0;
            mechanism = ZMQ_PLAIN;
            return 0;
        }
        break;

    case ZMQ_PLAIN_PASSWORD:
        if (optvallen_ == 0 && optval_ == NULL) {
            mechanism = ZMQ_NULL;
            return 0;
        }
        else if (optvallen_ > 0 && optvallen_ < 256 && optval_ != NULL) {
            plain_password.assign ((const char *) optval_, optvallen_);
            as_server = 0;
            mechanism = ZMQ_PLAIN;
            return 0;
        }
        break;

    case ZMQ_ZAP_DOMAIN:
        if (optvallen_ < 256) {
            zap_domain.assign ((const char *) optval_, optvallen_);
            return 0;
        }
        break;

        //  If curve encryption isn't built, these options provoke EINVAL
#ifdef ZMQ_HAVE_CURVE
    case ZMQ_CURVE_SERVER:
        if (is_int && (value == 0 || value == 1)) {
            as_server = value;
            mechanism = value? ZMQ_CURVE: ZMQ_NULL;
            return 0;
        }
        break;

    case ZMQ_CURVE_PUBLICKEY:
        //  TODO: refactor repeated code for these three options
        //  into set_curve_key (destination, optval, optlen) method
        //  ==> set_curve_key (curve_public_key, optval_, optvallen_);
        if (optvallen_ == CURVE_KEYSIZE) {
            memcpy (curve_public_key, optval_, CURVE_KEYSIZE);
            mechanism = ZMQ_CURVE;
            return 0;
        }
        else if (optvallen_ == CURVE_KEYSIZE_Z85 + 1) {
            if (zmq_z85_decode (curve_public_key, (char *) optval_)) {
                mechanism = ZMQ_CURVE;
                return 0;
            }
        }
        else
            //  Deprecated, not symmetrical with zmq_getsockopt
            if (optvallen_ == CURVE_KEYSIZE_Z85) {
                char z85_key [CURVE_KEYSIZE_Z85 + 1];
                memcpy (z85_key, (char *) optval_, CURVE_KEYSIZE_Z85);
                z85_key [CURVE_KEYSIZE_Z85] = 0;
                if (zmq_z85_decode (curve_public_key, z85_key)) {
                    mechanism = ZMQ_CURVE;
                    return 0;
                }
            }
        break;

    case ZMQ_CURVE_SECRETKEY:
        if (optvallen_ == CURVE_KEYSIZE) {
            memcpy (curve_secret_key, optval_, CURVE_KEYSIZE);
            mechanism = ZMQ_CURVE;
            return 0;
        }
        else if (optvallen_ == CURVE_KEYSIZE_Z85 + 1) {
            if (zmq_z85_decode (curve_secret_key, (char *) optval_)) {
                mechanism = ZMQ_CURVE;
                return 0;
            }
        }
        else
            //  Deprecated, not symmetrical with zmq_getsockopt
            if (optvallen_ == CURVE_KEYSIZE_Z85) {
                char z85_key [CURVE_KEYSIZE_Z85 + 1];
                memcpy (z85_key, (char *) optval_, CURVE_KEYSIZE_Z85);
                z85_key [CURVE_KEYSIZE_Z85] = 0;
                if (zmq_z85_decode (curve_secret_key, z85_key)) {
                    mechanism = ZMQ_CURVE;
                    return 0;
                }
            }
        break;

    case ZMQ_CURVE_SERVERKEY:
        if (optvallen_ == CURVE_KEYSIZE) {
            memcpy (curve_server_key, optval_, CURVE_KEYSIZE);
            mechanism = ZMQ_CURVE;
            as_server = 0;
            return 0;
        }
        else if (optvallen_ == CURVE_KEYSIZE_Z85 + 1) {
            if (zmq_z85_decode (curve_server_key, (char *) optval_)) {
                mechanism = ZMQ_CURVE;
                as_server = 0;
                return 0;
            }
        }
        else
            //  Deprecated, not symmetrical with zmq_getsockopt
            if (optvallen_ == CURVE_KEYSIZE_Z85) {
                char z85_key [CURVE_KEYSIZE_Z85 + 1];
                memcpy (z85_key, (char *) optval_, CURVE_KEYSIZE_Z85);
                z85_key [CURVE_KEYSIZE_Z85] = 0;
                if (zmq_z85_decode (curve_server_key, z85_key)) {
                    mechanism = ZMQ_CURVE;
                    as_server = 0;
                    return 0;
                }
            }
        break;
#endif

    case ZMQ_CONFLATE:
        if (is_int && (value == 0 || value == 1)) {
            conflate = (value != 0);
            return 0;
        }
        break;

        //  If libgssapi isn't installed, these options provoke EINVAL
#ifdef HAVE_LIBGSSAPI_KRB5
    case ZMQ_GSSAPI_SERVER:
        if (is_int && (value == 0 || value == 1)) {
            as_server = value;
            mechanism = ZMQ_GSSAPI;
            return 0;
        }
        break;

    case ZMQ_GSSAPI_PRINCIPAL:
        if (optvallen_ > 0 && optvallen_ < 256 && optval_ != NULL) {
            gss_principal.assign ((const char *) optval_, optvallen_);
            mechanism = ZMQ_GSSAPI;
            return 0;
        }
        break;

    case ZMQ_GSSAPI_SERVICE_PRINCIPAL:
        if (optvallen_ > 0 && optvallen_ < 256 && optval_ != NULL) {
            gss_service_principal.assign ((const char *) optval_, optvallen_);
            mechanism = ZMQ_GSSAPI;
            as_server = 0;
            return 0;
        }
        break;

    case ZMQ_GSSAPI_PLAINTEXT:
        if (is_int && (value == 0 || value == 1)) {
            gss_plaintext = (value != 0);
            return 0;
        }
        break;
#endif

    case ZMQ_HANDSHAKE_IVL:
        if (is_int && value >= 0) {
            handshake_ivl = value;
            return 0;
        }
        break;

    case ZMQ_INVERT_MATCHING:
        if (is_int) {
            invert_matching = (value != 0);
            return 0;
        }
        break;

    case ZMQ_HEARTBEAT_IVL:
        if (is_int && value >= 0) {
            heartbeat_interval = value;
            return 0;
        }
        break;

    case ZMQ_HEARTBEAT_TTL:
        // Convert this to deciseconds from milliseconds
        value = value / 100;
        if (is_int && value >= 0 && value <= 6553) {
            heartbeat_ttl = (uint16_t)value;
            return 0;
        }
        break;

    case ZMQ_HEARTBEAT_TIMEOUT:
        if (is_int && value >= 0) {
            heartbeat_timeout = value;
            return 0;
        }
        break;

#ifdef ZMQ_HAVE_VMCI
    case ZMQ_VMCI_BUFFER_SIZE:
        if (optvallen_ == sizeof (uint64_t)) {
            vmci_buffer_size = *((uint64_t*) optval_);
            return 0;
        }
        break;

    case ZMQ_VMCI_BUFFER_MIN_SIZE:
        if (optvallen_ == sizeof (uint64_t)) {
            vmci_buffer_min_size = *((uint64_t*) optval_);
            return 0;
        }
        break;

    case ZMQ_VMCI_BUFFER_MAX_SIZE:
        if (optvallen_ == sizeof (uint64_t)) {
            vmci_buffer_max_size = *((uint64_t*) optval_);
            return 0;
        }
        break;

    case ZMQ_VMCI_CONNECT_TIMEOUT:
        if (optvallen_ == sizeof (int)) {
            vmci_connect_timeout = *((int*) optval_);
            return 0;
        }
        break;
#endif

    case ZMQ_USE_FD:
        if (is_int && value >= -1) {
            use_fd = value;
            return 0;
        }
        break;

    default:
#if defined (ZMQ_ACT_MILITANT)
        //  There are valid scenarios for probing with unknown socket option
        //  values, e.g. to check if security is enabled or not. This will not
        //  provoke a militant assert. However, passing bad values to a valid
        //  socket option will, if ZMQ_ACT_MILITANT is defined.
        malformed = false;
#endif
        break;
    }
#if defined (ZMQ_ACT_MILITANT)
    //  There is no valid use case for passing an error back to the application
    //  when it sent malformed arguments to a socket option. Use ./configure
    //  --with-militant to enable this checking.
    if (malformed)
        zmq_assert (false);
#endif
    errno = EINVAL;
    return -1;
}
Example #18
0
void zmq::generic_mtrie_t<T>::rm_helper (value_t *pipe_,
                                         unsigned char **buff_,
                                         size_t buffsize_,
                                         size_t maxbuffsize_,
                                         void (*func_) (prefix_t data_,
                                                        size_t size_,
                                                        Arg arg_),
                                         Arg arg_,
                                         bool call_on_uniq_)
{
    //  Remove the subscription from this node.
    if (pipes && pipes->erase (pipe_)) {
        if (!call_on_uniq_ || pipes->empty ()) {
            func_ (*buff_, buffsize_, arg_);
        }

        if (pipes->empty ()) {
            LIBZMQ_DELETE (pipes);
        }
    }

    //  Adjust the buffer.
    if (buffsize_ >= maxbuffsize_) {
        maxbuffsize_ = buffsize_ + 256;
        *buff_ = (unsigned char *) realloc (*buff_, maxbuffsize_);
        alloc_assert (*buff_);
    }

    //  If there are no subnodes in the trie, return.
    if (count == 0)
        return;

    //  If there's one subnode (optimisation).
    if (count == 1) {
        (*buff_)[buffsize_] = min;
        buffsize_++;
        next.node->rm_helper (pipe_, buff_, buffsize_, maxbuffsize_, func_,
                              arg_, call_on_uniq_);

        //  Prune the node if it was made redundant by the removal
        if (next.node->is_redundant ()) {
            LIBZMQ_DELETE (next.node);
            count = 0;
            --live_nodes;
            zmq_assert (live_nodes == 0);
        }
        return;
    }

    //  If there are multiple subnodes.
    //
    //  New min non-null character in the node table after the removal
    unsigned char new_min = min + count - 1;
    //  New max non-null character in the node table after the removal
    unsigned char new_max = min;
    for (unsigned short c = 0; c != count; c++) {
        (*buff_)[buffsize_] = min + c;
        if (next.table[c]) {
            next.table[c]->rm_helper (pipe_, buff_, buffsize_ + 1, maxbuffsize_,
                                      func_, arg_, call_on_uniq_);

            //  Prune redundant nodes from the mtrie
            if (next.table[c]->is_redundant ()) {
                LIBZMQ_DELETE (next.table[c]);

                zmq_assert (live_nodes > 0);
                --live_nodes;
            } else {
                //  The node is not redundant, so it's a candidate for being
                //  the new min/max node.
                //
                //  We loop through the node array from left to right, so the
                //  first non-null, non-redundant node encountered is the new
                //  minimum index. Conversely, the last non-redundant, non-null
                //  node encountered is the new maximum index.
                if (c + min < new_min)
                    new_min = c + min;
                if (c + min > new_max)
                    new_max = c + min;
            }
        }
    }

    zmq_assert (count > 1);

    //  Free the node table if it's no longer used.
    if (live_nodes == 0) {
        free (next.table);
        next.table = NULL;
        count = 0;
    }
    //  Compact the node table if possible
    else if (live_nodes == 1) {
        //  If there's only one live node in the table we can
        //  switch to using the more compact single-node
        //  representation
        zmq_assert (new_min == new_max);
        zmq_assert (new_min >= min && new_min < min + count);
        generic_mtrie_t *node = next.table[new_min - min];
        zmq_assert (node);
        free (next.table);
        next.node = node;
        count = 1;
        min = new_min;
    } else if (new_min > min || new_max < min + count - 1) {
        zmq_assert (new_max - new_min + 1 > 1);

        generic_mtrie_t **old_table = next.table;
        zmq_assert (new_min > min || new_max < min + count - 1);
        zmq_assert (new_min >= min);
        zmq_assert (new_max <= min + count - 1);
        zmq_assert (new_max - new_min + 1 < count);

        count = new_max - new_min + 1;
        next.table =
          (generic_mtrie_t **) malloc (sizeof (generic_mtrie_t *) * count);
        alloc_assert (next.table);

        memmove (next.table, old_table + (new_min - min),
                 sizeof (generic_mtrie_t *) * count);
        free (old_table);

        min = new_min;
    }
}
Example #19
0
int zmq::router_t::xrecv (msg_t *msg_, int flags_)
{
    //  if there is a prefetched identity, return it.
    if (prefetched == 2)
    {
        int rc = msg_->init_size (prefetched_id.size ());
        errno_assert (rc == 0);
        memcpy (msg_->data (), prefetched_id.data (), prefetched_id.size ());
        msg_->set_flags (msg_t::more);
        prefetched = 1;
        return 0;
    }

    //  If there is a prefetched message, return it.
    if (prefetched == 1) {
        int rc = msg_->move (prefetched_msg);
        errno_assert (rc == 0);
        more_in = msg_->flags () & msg_t::more ? true : false;
        prefetched = 0;
        return 0;
    }

    pipe_t *pipe = NULL;
    while (true) {

        //  Get next message part.
        int rc = fq.recvpipe (msg_, flags_, &pipe);
        if (rc != 0)
            return -1;

        //  If identity is received, change the key assigned to the pipe.
        if (likely (!(msg_->flags () & msg_t::identity)))
            break;

        zmq_assert (!more_in);

        //  Empty identity means we can preserve the auto-generated identity
        if (msg_->size ()) {
            blob_t identity ((unsigned char*) msg_->data (), msg_->size ());
            outpipes_t::iterator it = outpipes.find (identity);
            if (it == outpipes.end ()) {
                //  Find the pipe and change its identity
                bool changed = false;
                it = outpipes.begin ();
                while (it != outpipes.end ()) {
                    if (it->second.pipe == pipe) {
                        pipe->set_identity (identity);
                        outpipes.erase (it);
                        outpipe_t outpipe = {pipe, true};
                        if (!outpipes.insert (
                            outpipes_t::value_type (identity, outpipe)).second)
                            zmq_assert (false);
                        changed = true;
                        break;
                    }
                    ++it;
                }
                zmq_assert (changed);
            }
        }
    }

    //  If we are in the middle of reading a message, just return the next part.
    if (more_in) {
        more_in = msg_->flags () & msg_t::more ? true : false;
        return 0;
    }
 
    //  We are at the beginning of a new message. Move the message part we
    //  have to the prefetched and return the ID of the peer instead.
    int rc = prefetched_msg.move (*msg_);
    errno_assert (rc == 0);
    prefetched = 1;
    rc = msg_->close ();
    errno_assert (rc == 0);

    blob_t identity = pipe->get_identity ();
    rc = msg_->init_size (identity.size ());
    errno_assert (rc == 0);
    memcpy (msg_->data (), identity.data (), identity.size ());
    msg_->set_flags (msg_t::more);
    return 0;
}
Example #20
0
typename zmq::generic_mtrie_t<T>::rm_result zmq::generic_mtrie_t<T>::rm_helper (
  prefix_t prefix_, size_t size_, value_t *pipe_)
{
    if (!size_) {
        if (!pipes)
            return not_found;

        typename pipes_t::size_type erased = pipes->erase (pipe_);
        if (pipes->empty ()) {
            zmq_assert (erased == 1);
            LIBZMQ_DELETE (pipes);
            return last_value_removed;
        }
        return (erased == 1) ? values_remain : not_found;
    }

    unsigned char c = *prefix_;
    if (!count || c < min || c >= min + count)
        return not_found;

    generic_mtrie_t *next_node = count == 1 ? next.node : next.table[c - min];

    if (!next_node)
        return not_found;

    rm_result ret = next_node->rm_helper (prefix_ + 1, size_ - 1, pipe_);

    if (next_node->is_redundant ()) {
        LIBZMQ_DELETE (next_node);
        zmq_assert (count > 0);

        if (count == 1) {
            next.node = 0;
            count = 0;
            --live_nodes;
            zmq_assert (live_nodes == 0);
        } else {
            next.table[c - min] = 0;
            zmq_assert (live_nodes > 1);
            --live_nodes;

            //  Compact the table if possible
            if (live_nodes == 1) {
                //  If there's only one live node in the table we can
                //  switch to using the more compact single-node
                //  representation
                unsigned short i;
                for (i = 0; i < count; ++i)
                    if (next.table[i])
                        break;

                zmq_assert (i < count);
                min += i;
                count = 1;
                generic_mtrie_t *oldp = next.table[i];
                free (next.table);
                next.node = oldp;
            } else if (c == min) {
                //  We can compact the table "from the left"
                unsigned short i;
                for (i = 1; i < count; ++i)
                    if (next.table[i])
                        break;

                zmq_assert (i < count);
                min += i;
                count -= i;
                generic_mtrie_t **old_table = next.table;
                next.table = (generic_mtrie_t **) malloc (
                  sizeof (generic_mtrie_t *) * count);
                alloc_assert (next.table);
                memmove (next.table, old_table + i,
                         sizeof (generic_mtrie_t *) * count);
                free (old_table);
            } else if (c == min + count - 1) {
                //  We can compact the table "from the right"
                unsigned short i;
                for (i = 1; i < count; ++i)
                    if (next.table[count - 1 - i])
                        break;

                zmq_assert (i < count);
                count -= i;
                generic_mtrie_t **old_table = next.table;
                next.table = (generic_mtrie_t **) malloc (
                  sizeof (generic_mtrie_t *) * count);
                alloc_assert (next.table);
                memmove (next.table, old_table,
                         sizeof (generic_mtrie_t *) * count);
                free (old_table);
            }
        }
    }

    return ret;
}
Example #21
0
void zmq::socket_base_t::xwrite_activated (pipe_t *pipe_)
{
    zmq_assert (false);
}
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 (options.tcp_send_buffer_size);
        alloc_assert (encoder);

        decoder = new (std::nothrow) raw_decoder_t (options.tcp_recv_buffer_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 ();
}
Example #23
0
void zmq::socket_base_t::out_event ()
{
    zmq_assert (false);
}
void zmq::stream_engine_t::in_event ()
{
    zmq_assert (!io_error);

    //  If still handshaking, receive and process the greeting message.
    if (unlikely (handshaking))
        if (!handshake ())
            return;

    zmq_assert (decoder);

    //  If there has been an I/O error, stop polling.
    if (input_stopped) {
        rm_fd (handle);
        io_error = true;
        return;
    }

    //  If there's no data to process in the buffer...
    if (!insize) {

        //  Retrieve the buffer and read as much data as possible.
        //  Note that buffer can be arbitrarily large. However, we assume
        //  the underlying TCP layer has fixed buffer size and thus the
        //  number of bytes read will be always limited.
        size_t bufsize = 0;
        decoder->get_buffer (&inpos, &bufsize);

        const int rc = tcp_read (s, inpos, bufsize);

        if (rc == 0) {
            error (connection_error);
            return;
        }
        if (rc == -1) {
            if (errno != EAGAIN)
                error (connection_error);
            return;
        }

        //  Adjust input size
        insize = static_cast <size_t> (rc);
        // Adjust buffer size to received bytes
        decoder->resize_buffer(insize);
    }

    int rc = 0;
    size_t processed = 0;

    while (insize > 0) {
        rc = decoder->decode (inpos, insize, processed);
        zmq_assert (processed <= insize);
        inpos += processed;
        insize -= processed;
        if (rc == 0 || rc == -1)
            break;
        rc = (this->*process_msg) (decoder->msg ());
        if (rc == -1)
            break;
    }

    //  Tear down the connection if we have failed to decode input data
    //  or the session has rejected the message.
    if (rc == -1) {
        if (errno != EAGAIN) {
            error (protocol_error);
            return;
        }
        input_stopped = true;
        reset_pollin (handle);
    }

    session->flush ();
}
Example #25
0
int zmq_poll (zmq_pollitem_t *items_, int nitems_, long timeout_)
{
#if defined ZMQ_POLL_BASED_ON_POLL
    if (unlikely (nitems_ < 0)) {
        errno = EINVAL;
        return -1;
    }
    if (unlikely (nitems_ == 0)) {
        if (timeout_ == 0)
            return 0;
#if defined ZMQ_HAVE_WINDOWS
        Sleep (timeout_ > 0 ? timeout_ : INFINITE);
        return 0;
#elif defined ZMQ_HAVE_ANDROID
        usleep (timeout_ * 1000);
        return 0;
#else
        return usleep (timeout_ * 1000);
#endif
    }

    if (!items_) {
        errno = EFAULT;
        return -1;
    }

    zmq::clock_t clock;
    uint64_t now = 0;
    uint64_t end = 0;
    pollfd spollfds[ZMQ_POLLITEMS_DFLT];
    pollfd *pollfds = spollfds;

    if (nitems_ > ZMQ_POLLITEMS_DFLT) {
        pollfds = (pollfd*) malloc (nitems_ * sizeof (pollfd));
        alloc_assert (pollfds);
    }

    //  Build pollset for poll () system call.
    for (int i = 0; i != nitems_; i++) {

        //  If the poll item is a 0MQ socket, we poll on the file descriptor
        //  retrieved by the ZMQ_FD socket option.
        if (items_ [i].socket) {
            size_t zmq_fd_size = sizeof (zmq::fd_t);
            if (zmq_getsockopt (items_ [i].socket, ZMQ_FD, &pollfds [i].fd,
                &zmq_fd_size) == -1) {
                if (pollfds != spollfds)
                    free (pollfds);
                return -1;
            }
            pollfds [i].events = items_ [i].events ? POLLIN : 0;
        }
        //  Else, the poll item is a raw file descriptor. Just convert the
        //  events to normal POLLIN/POLLOUT for poll ().
        else {
            pollfds [i].fd = items_ [i].fd;
            pollfds [i].events =
                (items_ [i].events & ZMQ_POLLIN ? POLLIN : 0) |
                (items_ [i].events & ZMQ_POLLOUT ? POLLOUT : 0);
        }
    }

    bool first_pass = true;
    int nevents = 0;

    while (true) {
        //  Compute the timeout for the subsequent poll.
        int timeout;
        if (first_pass)
            timeout = 0;
        else
        if (timeout_ < 0)
            timeout = -1;
        else
            timeout = end - now;

        //  Wait for events.
        while (true) {
            int rc = poll (pollfds, nitems_, timeout);
            if (rc == -1 && errno == EINTR) {
                if (pollfds != spollfds)
                    free (pollfds);
                return -1;
            }
            errno_assert (rc >= 0);
            break;
        }
        //  Check for the events.
        for (int i = 0; i != nitems_; i++) {

            items_ [i].revents = 0;

            //  The poll item is a 0MQ socket. Retrieve pending events
            //  using the ZMQ_EVENTS socket option.
            if (items_ [i].socket) {
                size_t zmq_events_size = sizeof (uint32_t);
                uint32_t zmq_events;
                if (zmq_getsockopt (items_ [i].socket, ZMQ_EVENTS, &zmq_events,
                    &zmq_events_size) == -1) {
                    if (pollfds != spollfds)
                        free (pollfds);
                    return -1;
                }
                if ((items_ [i].events & ZMQ_POLLOUT) &&
                      (zmq_events & ZMQ_POLLOUT))
                    items_ [i].revents |= ZMQ_POLLOUT;
                if ((items_ [i].events & ZMQ_POLLIN) &&
                      (zmq_events & ZMQ_POLLIN))
                    items_ [i].revents |= ZMQ_POLLIN;
            }
            //  Else, the poll item is a raw file descriptor, simply convert
            //  the events to zmq_pollitem_t-style format.
            else {
                if (pollfds [i].revents & POLLIN)
                    items_ [i].revents |= ZMQ_POLLIN;
                if (pollfds [i].revents & POLLOUT)
                    items_ [i].revents |= ZMQ_POLLOUT;
                if (pollfds [i].revents & ~(POLLIN | POLLOUT))
                    items_ [i].revents |= ZMQ_POLLERR;
            }

            if (items_ [i].revents)
                nevents++;
        }

        //  If timout is zero, exit immediately whether there are events or not.
        if (timeout_ == 0)
            break;

        //  If there are events to return, we can exit immediately.
        if (nevents)
            break;

        //  At this point we are meant to wait for events but there are none.
        //  If timeout is infinite we can just loop until we get some events.
        if (timeout_ < 0) {
            if (first_pass)
                first_pass = false;
            continue;
        }

        //  The timeout is finite and there are no events. In the first pass
        //  we get a timestamp of when the polling have begun. (We assume that
        //  first pass have taken negligible time). We also compute the time
        //  when the polling should time out.
        if (first_pass) {
            now = clock.now_ms ();
            end = now + timeout_;
            if (now == end)
                break;
            first_pass = false;
            continue;
        }

        //  Find out whether timeout have expired.
        now = clock.now_ms ();
        if (now >= end)
            break;
    }

    if (pollfds != spollfds)
        free (pollfds);
    return nevents;

#elif defined ZMQ_POLL_BASED_ON_SELECT

    if (unlikely (nitems_ < 0)) {
        errno = EINVAL;
        return -1;
    }
    if (unlikely (nitems_ == 0)) {
        if (timeout_ == 0)
            return 0;
#if defined ZMQ_HAVE_WINDOWS
        Sleep (timeout_ > 0 ? timeout_ : INFINITE);
        return 0;
#else
        return usleep (timeout_ * 1000);
#endif
    }
    zmq::clock_t clock;
    uint64_t now = 0;
    uint64_t end = 0;

    //  Ensure we do not attempt to select () on more than FD_SETSIZE
    //  file descriptors.
    zmq_assert (nitems_ <= FD_SETSIZE);

    fd_set pollset_in;
    FD_ZERO (&pollset_in);
    fd_set pollset_out;
    FD_ZERO (&pollset_out);
    fd_set pollset_err;
    FD_ZERO (&pollset_err);

    zmq::fd_t maxfd = 0;

    //  Build the fd_sets for passing to select ().
    for (int i = 0; i != nitems_; i++) {

        //  If the poll item is a 0MQ socket we are interested in input on the
        //  notification file descriptor retrieved by the ZMQ_FD socket option.
        if (items_ [i].socket) {
            size_t zmq_fd_size = sizeof (zmq::fd_t);
            zmq::fd_t notify_fd;
            if (zmq_getsockopt (items_ [i].socket, ZMQ_FD, &notify_fd,
                &zmq_fd_size) == -1)
                return -1;
            if (items_ [i].events) {
                FD_SET (notify_fd, &pollset_in);
                if (maxfd < notify_fd)
                    maxfd = notify_fd;
            }
        }
        //  Else, the poll item is a raw file descriptor. Convert the poll item
        //  events to the appropriate fd_sets.
        else {
            if (items_ [i].events & ZMQ_POLLIN)
                FD_SET (items_ [i].fd, &pollset_in);
            if (items_ [i].events & ZMQ_POLLOUT)
                FD_SET (items_ [i].fd, &pollset_out);
            if (items_ [i].events & ZMQ_POLLERR)
                FD_SET (items_ [i].fd, &pollset_err);
            if (maxfd < items_ [i].fd)
                maxfd = items_ [i].fd;
        }
    }

    bool first_pass = true;
    int nevents = 0;
    fd_set inset, outset, errset;

    while (true) {

        //  Compute the timeout for the subsequent poll.
        timeval timeout;
        timeval *ptimeout;
        if (first_pass) {
            timeout.tv_sec = 0;
            timeout.tv_usec = 0;
            ptimeout = &timeout;
        }
        else
        if (timeout_ < 0)
            ptimeout = NULL;
        else {
            timeout.tv_sec = (long) ((end - now) / 1000);
            timeout.tv_usec = (long) ((end - now) % 1000 * 1000);
            ptimeout = &timeout;
        }

        //  Wait for events. Ignore interrupts if there's infinite timeout.
        while (true) {
            memcpy (&inset, &pollset_in, sizeof (fd_set));
            memcpy (&outset, &pollset_out, sizeof (fd_set));
            memcpy (&errset, &pollset_err, sizeof (fd_set));
#if defined ZMQ_HAVE_WINDOWS
            int rc = select (0, &inset, &outset, &errset, ptimeout);
            if (unlikely (rc == SOCKET_ERROR)) {
                errno = zmq::wsa_error_to_errno (WSAGetLastError ());
                wsa_assert (errno == ENOTSOCK);
                return -1;
            }
#else
            int rc = select (maxfd + 1, &inset, &outset, &errset, ptimeout);
            if (unlikely (rc == -1)) {
                errno_assert (errno == EINTR || errno == EBADF);
                return -1;
            }
#endif
            break;
        }

        //  Check for the events.
        for (int i = 0; i != nitems_; i++) {

            items_ [i].revents = 0;

            //  The poll item is a 0MQ socket. Retrieve pending events
            //  using the ZMQ_EVENTS socket option.
            if (items_ [i].socket) {
                size_t zmq_events_size = sizeof (uint32_t);
                uint32_t zmq_events;
                if (zmq_getsockopt (items_ [i].socket, ZMQ_EVENTS, &zmq_events,
                      &zmq_events_size) == -1)
                    return -1;
                if ((items_ [i].events & ZMQ_POLLOUT) &&
                      (zmq_events & ZMQ_POLLOUT))
                    items_ [i].revents |= ZMQ_POLLOUT;
                if ((items_ [i].events & ZMQ_POLLIN) &&
                      (zmq_events & ZMQ_POLLIN))
                    items_ [i].revents |= ZMQ_POLLIN;
            }
            //  Else, the poll item is a raw file descriptor, simply convert
            //  the events to zmq_pollitem_t-style format.
            else {
                if (FD_ISSET (items_ [i].fd, &inset))
                    items_ [i].revents |= ZMQ_POLLIN;
                if (FD_ISSET (items_ [i].fd, &outset))
                    items_ [i].revents |= ZMQ_POLLOUT;
                if (FD_ISSET (items_ [i].fd, &errset))
                    items_ [i].revents |= ZMQ_POLLERR;
            }

            if (items_ [i].revents)
                nevents++;
        }

        //  If timout is zero, exit immediately whether there are events or not.
        if (timeout_ == 0)
            break;

        //  If there are events to return, we can exit immediately.
        if (nevents)
            break;

        //  At this point we are meant to wait for events but there are none.
        //  If timeout is infinite we can just loop until we get some events.
        if (timeout_ < 0) {
            if (first_pass)
                first_pass = false;
            continue;
        }

        //  The timeout is finite and there are no events. In the first pass
        //  we get a timestamp of when the polling have begun. (We assume that
        //  first pass have taken negligible time). We also compute the time
        //  when the polling should time out.
        if (first_pass) {
            now = clock.now_ms ();
            end = now + timeout_;
            if (now == end)
                break;
            first_pass = false;
            continue;
        }

        //  Find out whether timeout have expired.
        now = clock.now_ms ();
        if (now >= end)
            break;
    }

    return nevents;

#else
    //  Exotic platforms that support neither poll() nor select().
    errno = ENOTSUP;
    return -1;
#endif
}
void zmq::stream_engine_t::out_event ()
{
    zmq_assert (!io_error);

    //  If write buffer is empty, try to read new data from the encoder.
    if (!outsize) {

        //  Even when we stop polling as soon as there is no
        //  data to send, the poller may invoke out_event one
        //  more time due to 'speculative write' optimisation.
        if (unlikely (encoder == NULL)) {
            zmq_assert (handshaking);
            return;
        }

        outpos = NULL;
        outsize = encoder->encode (&outpos, 0);

        while (outsize < options.tcp_send_buffer_size) {
            if ((this->*next_msg) (&tx_msg) == -1)
                break;
            encoder->load_msg (&tx_msg);
            unsigned char *bufptr = outpos + outsize;
            size_t n = encoder->encode (&bufptr, options.tcp_send_buffer_size - outsize);
            zmq_assert (n > 0);
            if (outpos == NULL)
                outpos = bufptr;
            outsize += n;
        }

        //  If there is no data to send, stop polling for output.
        if (outsize == 0) {
            output_stopped = true;
            reset_pollout (handle);
            return;
        }
    }

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

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

    outpos += nbytes;
    outsize -= nbytes;

    //  If we are still handshaking and there are no data
    //  to send, stop polling for output.
    if (unlikely (handshaking))
        if (outsize == 0)
            reset_pollout (handle);
}
Example #27
0
bool zmq::trie_t::add (unsigned char *prefix_, size_t size_)
{
    //  We are at the node corresponding to the prefix. We are done.
    if (!size_) {
        ++refcnt;
        return refcnt == 1;
    }

    unsigned char c = *prefix_;
    if (c < min || c >= min + count) {

        //  The character is out of range of currently handled
        //  charcters. We have to extend the table.
        if (!count) {
            min = c;
            count = 1;
            next.node = NULL;
        }
        else
        if (count == 1) {
            unsigned char oldc = min;
            trie_t *oldp = next.node;
            count = (min < c ? c - min : min - c) + 1;
            next.table = (trie_t**)
                malloc (sizeof (trie_t*) * count);
            alloc_assert (next.table);
            for (unsigned short i = 0; i != count; ++i)
                next.table [i] = 0;
            min = std::min (min, c);
            next.table [oldc - min] = oldp;
        }
        else
        if (min < c) {
            //  The new character is above the current character range.
            unsigned short old_count = count;
            count = c - min + 1;
            next.table = (trie_t**) realloc ((void*) next.table,
                sizeof (trie_t*) * count);
            zmq_assert (next.table);
            for (unsigned short i = old_count; i != count; i++)
                next.table [i] = NULL;
        }
        else {

            //  The new character is below the current character range.
            unsigned short old_count = count;
            count = (min + old_count) - c;
            next.table = (trie_t**) realloc ((void*) next.table,
                sizeof (trie_t*) * count);
            zmq_assert (next.table);
            memmove (next.table + min - c, next.table,
                old_count * sizeof (trie_t*));
            for (unsigned short i = 0; i != min - c; i++)
                next.table [i] = NULL;
            min = c;
        }
    }

    //  If next node does not exist, create one.
    if (count == 1) {
        if (!next.node) {
            next.node = new (std::nothrow) trie_t;
            alloc_assert (next.node);
            ++live_nodes;
            zmq_assert (live_nodes == 1);
        }
        return next.node->add (prefix_ + 1, size_ - 1);
    }
    else {
        if (!next.table [c - min]) {
            next.table [c - min] = new (std::nothrow) trie_t;
            alloc_assert (next.table [c - min]);
            ++live_nodes;
            zmq_assert (live_nodes > 1);
        }
        return next.table [c - min]->add (prefix_ + 1, size_ - 1);
    }
}
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 (options.tcp_send_buffer_size);
        alloc_assert (encoder);

        decoder = new (std::nothrow) v1_decoder_t (options.tcp_recv_buffer_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 (
           options.tcp_send_buffer_size);
        alloc_assert (encoder);

        decoder = new (std::nothrow) v1_decoder_t (
            options.tcp_recv_buffer_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 (options.tcp_send_buffer_size);
        alloc_assert (encoder);

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

        decoder = new (std::nothrow) v2_decoder_t (
                options.tcp_recv_buffer_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 {
            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;
}
Example #29
0
void zmq::xpub_t::xattach_pipes (class reader_t *inpipe_,
    class writer_t *outpipe_, const blob_t &peer_identity_)
{
    zmq_assert (!inpipe_ && outpipe_);
    dist.attach (outpipe_);
}
Example #30
0
void zmq::own_t::set_owner (own_t *owner_)
{
    zmq_assert (!owner);
    owner = owner_;
}