zmq::server_t::~server_t () { zmq_assert (outpipes.empty ()); }
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; }
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; }
void zmq::socket_base_t::xhiccuped (pipe_t *pipe_) { zmq_assert (false); }
void zmq::socket_base_t::timer_event (int id_) { zmq_assert (false); }
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; }
zmq::router_t::~router_t () { zmq_assert (outpipes.empty ()); prefetched_msg.close (); }
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; }
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); }
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 (); }
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; }
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 }
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; }
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; } }
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; }
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; }
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 (); }
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 (); }
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, ¬ify_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); }
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; }
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_); }
void zmq::own_t::set_owner (own_t *owner_) { zmq_assert (!owner); owner = owner_; }