zmq::socket_base_t *zmq::socket_base_t::create (int type_, class ctx_t *parent_, uint32_t tid_, int sid_) { socket_base_t *s = NULL; switch (type_) { case ZMQ_PAIR: s = new (std::nothrow) pair_t (parent_, tid_, sid_); break; case ZMQ_PUB: s = new (std::nothrow) pub_t (parent_, tid_, sid_); break; case ZMQ_SUB: s = new (std::nothrow) sub_t (parent_, tid_, sid_); break; case ZMQ_REQ: s = new (std::nothrow) req_t (parent_, tid_, sid_); break; case ZMQ_REP: s = new (std::nothrow) rep_t (parent_, tid_, sid_); break; case ZMQ_DEALER: s = new (std::nothrow) dealer_t (parent_, tid_, sid_); break; case ZMQ_ROUTER: s = new (std::nothrow) router_t (parent_, tid_, sid_); break; case ZMQ_PULL: s = new (std::nothrow) pull_t (parent_, tid_, sid_); break; case ZMQ_PUSH: s = new (std::nothrow) push_t (parent_, tid_, sid_); break; case ZMQ_XPUB: s = new (std::nothrow) xpub_t (parent_, tid_, sid_); break; case ZMQ_XSUB: s = new (std::nothrow) xsub_t (parent_, tid_, sid_); break; case ZMQ_STREAM: s = new (std::nothrow) stream_t (parent_, tid_, sid_); break; case ZMQ_SERVER: s = new (std::nothrow) server_t (parent_, tid_, sid_); break; case ZMQ_CLIENT: s = new (std::nothrow) client_t (parent_, tid_, sid_); break; case ZMQ_RADIO: s = new (std::nothrow) radio_t (parent_, tid_, sid_); break; case ZMQ_DISH: s = new (std::nothrow) dish_t (parent_, tid_, sid_); break; case ZMQ_GATHER: s = new (std::nothrow) gather_t (parent_, tid_, sid_); break; case ZMQ_SCATTER: s = new (std::nothrow) scatter_t (parent_, tid_, sid_); break; case ZMQ_DGRAM: s = new (std::nothrow) dgram_t (parent_, tid_, sid_); break; default: errno = EINVAL; return NULL; } alloc_assert (s); if (s->mailbox == NULL) { s->destroyed = true; LIBZMQ_DELETE(s); return NULL; } return s; }
void zmq::session_base_t::start_connecting (bool wait_) { zmq_assert (connect); // Choose I/O thread to run connecter in. Given that we are already // running in an I/O thread, there must be at least one available. io_thread_t *io_thread = choose_io_thread (options.affinity); zmq_assert (io_thread); // Create the connecter object. if (addr->protocol == "tcp") { tcp_connecter_t *connecter = new (std::nothrow) tcp_connecter_t ( io_thread, this, options, addr, wait_); alloc_assert (connecter); launch_child (connecter); return; } #if !defined ZMQ_HAVE_WINDOWS && !defined ZMQ_HAVE_OPENVMS if (addr->protocol == "ipc") { ipc_connecter_t *connecter = new (std::nothrow) ipc_connecter_t ( io_thread, this, options, addr, wait_); alloc_assert (connecter); launch_child (connecter); return; } #endif #ifdef ZMQ_HAVE_OPENPGM // Both PGM and EPGM transports are using the same infrastructure. if (addr->protocol == "pgm" || addr->protocol == "epgm") { zmq_assert (options.type == ZMQ_PUB || options.type == ZMQ_XPUB || options.type == ZMQ_SUB || options.type == ZMQ_XSUB); // For EPGM transport with UDP encapsulation of PGM is used. bool const udp_encapsulation = addr->protocol == "epgm"; // At this point we'll create message pipes to the session straight // away. There's no point in delaying it as no concept of 'connect' // exists with PGM anyway. if (options.type == ZMQ_PUB || options.type == ZMQ_XPUB) { // PGM sender. pgm_sender_t *pgm_sender = new (std::nothrow) pgm_sender_t ( io_thread, options); alloc_assert (pgm_sender); int rc = pgm_sender->init (udp_encapsulation, addr->address.c_str ()); errno_assert (rc == 0); send_attach (this, pgm_sender); } else { // PGM receiver. pgm_receiver_t *pgm_receiver = new (std::nothrow) pgm_receiver_t ( io_thread, options); alloc_assert (pgm_receiver); int rc = pgm_receiver->init (udp_encapsulation, addr->address.c_str ()); errno_assert (rc == 0); send_attach (this, pgm_receiver); } return; } #endif zmq_assert (false); }
static int grid_usock_recv_raw (struct grid_usock *self, void *buf, size_t *len) { size_t sz; size_t length; ssize_t nbytes; struct iovec iov; struct msghdr hdr; unsigned char ctrl [256]; #if defined GRID_HAVE_MSG_CONTROL struct cmsghdr *cmsg; #endif /* If batch buffer doesn't exist, allocate it. The point of delayed deallocation to allow non-receiving sockets, such as TCP listening sockets, to do without the batch buffer. */ if (grid_slow (!self->in.batch)) { self->in.batch = grid_alloc (GRID_USOCK_BATCH_SIZE, "AIO batch buffer"); alloc_assert (self->in.batch); } /* Try to satisfy the recv request by data from the batch buffer. */ length = *len; sz = self->in.batch_len - self->in.batch_pos; if (sz) { if (sz > length) sz = length; memcpy (buf, self->in.batch + self->in.batch_pos, sz); self->in.batch_pos += sz; buf = ((char*) buf) + sz; length -= sz; if (!length) return 0; } /* If recv request is greater than the batch buffer, get the data directly into the place. Otherwise, read data to the batch buffer. */ if (length > GRID_USOCK_BATCH_SIZE) { iov.iov_base = buf; iov.iov_len = length; } else { iov.iov_base = self->in.batch; iov.iov_len = GRID_USOCK_BATCH_SIZE; } memset (&hdr, 0, sizeof (hdr)); hdr.msg_iov = &iov; hdr.msg_iovlen = 1; #if defined GRID_HAVE_MSG_CONTROL hdr.msg_control = ctrl; hdr.msg_controllen = sizeof (ctrl); #else *((int*) ctrl) = -1; hdr.msg_accrights = ctrl; hdr.msg_accrightslen = sizeof (int); #endif nbytes = recvmsg (self->s, &hdr, 0); /* Handle any possible errors. */ if (grid_slow (nbytes <= 0)) { if (grid_slow (nbytes == 0)) return -ECONNRESET; /* Zero bytes received. */ if (grid_fast (errno == EAGAIN || errno == EWOULDBLOCK)) nbytes = 0; else { /* If the peer closes the connection, return ECONNRESET. */ return -ECONNRESET; } } /* Extract the associated file descriptor, if any. */ if (nbytes > 0) { #if defined GRID_HAVE_MSG_CONTROL cmsg = CMSG_FIRSTHDR (&hdr); while (cmsg) { if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) { if (self->in.pfd) { *self->in.pfd = *((int*) CMSG_DATA (cmsg)); self->in.pfd = NULL; } else { grid_closefd (*((int*) CMSG_DATA (cmsg))); } break; } cmsg = CMSG_NXTHDR (&hdr, cmsg); } #else if (hdr.msg_accrightslen > 0) { grid_assert (hdr.msg_accrightslen == sizeof (int)); if (self->in.pfd) { *self->in.pfd = *((int*) hdr.msg_accrights); self->in.pfd = NULL; } else { grid_closefd (*((int*) hdr.msg_accrights)); } } #endif } /* If the data were received directly into the place we can return straight away. */ if (length > GRID_USOCK_BATCH_SIZE) { length -= nbytes; *len -= length; return 0; } /* New data were read to the batch buffer. Copy the requested amount of it to the user-supplied buffer. */ self->in.batch_len = nbytes; self->in.batch_pos = 0; if (nbytes) { sz = nbytes > (ssize_t)length ? length : (size_t)nbytes; memcpy (buf, self->in.batch, sz); length -= sz; self->in.batch_pos += sz; } *len -= length; return 0; }
void zmq::mtrie_t::rm_helper (pipe_t *pipe_, unsigned char **buff_, size_t buffsize_, size_t maxbuffsize_, void (*func_) (unsigned char *data_, size_t size_, void *arg_), void *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); 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); 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 = (mtrie_t**) malloc (sizeof (mtrie_t*) * count); alloc_assert (next.table); memmove (next.table, old_table + (new_min - min), sizeof (mtrie_t*) * count); free (old_table); min = new_min; } }
bool zmq::mtrie_t::add_helper (unsigned char *prefix_, size_t size_, pipe_t *pipe_) { // We are at the node corresponding to the prefix. We are done. if (!size_) { bool result = !pipes; if (!pipes) { pipes = new (std::nothrow) pipes_t; alloc_assert (pipes); } pipes->insert (pipe_); return result; } 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; mtrie_t *oldp = next.node; count = (min < c ? c - min : min - c) + 1; next.table = (mtrie_t**) malloc (sizeof (mtrie_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 = (mtrie_t**) realloc (next.table, sizeof (mtrie_t*) * count); alloc_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 = (mtrie_t**) realloc (next.table, sizeof (mtrie_t*) * count); alloc_assert (next.table); memmove (next.table + min - c, next.table, old_count * sizeof (mtrie_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) mtrie_t; alloc_assert (next.node); ++live_nodes; } return next.node->add_helper (prefix_ + 1, size_ - 1, pipe_); } else { if (!next.table [c - min]) { next.table [c - min] = new (std::nothrow) mtrie_t; alloc_assert (next.table [c - min]); ++live_nodes; } return next.table [c - min]->add_helper (prefix_ + 1, size_ - 1, pipe_); } }
static bool pfx_rm (pfx_node_t *node_, const unsigned char *prefix_, size_t size_, void *subscriber_) { if (!size_) { // Remove the subscription from this node. if (node_->subscribers) { pfx_node_t::subscribers_t::iterator it = node_->subscribers->find (subscriber_); if (it != node_->subscribers->end ()) { xs_assert (it->second); --it->second; if (!it->second) { node_->subscribers->erase (it); if (node_->subscribers->empty ()) { delete node_->subscribers; node_->subscribers = 0; } } } } return !node_->subscribers; } unsigned char c = *prefix_; if (!node_->count || c < node_->min || c >= node_->min + node_->count) return false; pfx_node_t *next_node = node_->count == 1 ? node_->next.node : node_->next.table [c - node_->min]; if (!next_node) return false; bool ret = pfx_rm (next_node, prefix_ + 1, size_ - 1, subscriber_); if (pfx_is_redundant (next_node)) { pfx_close (next_node); free (next_node); xs_assert (node_->count > 0); if (node_->count == 1) { node_->next.node = 0; node_->count = 0; --node_->live_nodes; xs_assert (node_->live_nodes == 0); } else { node_->next.table [c - node_->min] = 0; xs_assert (node_->live_nodes > 1); --node_->live_nodes; // Compact the table if possible. if (node_->live_nodes == 0) { // Free the node table if it's no longer used. free (node_->next.table); node_->next.table = NULL; node_->count = 0; } else if (node_->live_nodes == 1) { // If there's only one live node in the table we can // switch to using the more compact single-node // representation pfx_node_t *node = 0; for (unsigned short i = 0; i < node_->count; ++i) { if (node_->next.table [i]) { node = node_->next.table [i]; node_->min += i; break; } } xs_assert (node); free (node_->next.table); node_->next.node = node; node_->count = 1; } else if (c == node_->min) { // We can compact the table "from the left". unsigned char new_min = node_->min; for (unsigned short i = 1; i < node_->count; ++i) { if (node_->next.table [i]) { new_min = i + node_->min; break; } } xs_assert (new_min != node_->min); pfx_node_t **old_table = node_->next.table; xs_assert (new_min > node_->min); xs_assert (node_->count > new_min - node_->min); node_->count = node_->count - (new_min - node_->min); node_->next.table = (pfx_node_t**) malloc (sizeof (pfx_node_t*) * node_->count); alloc_assert (node_->next.table); memmove (node_->next.table, old_table + (new_min - node_->min), sizeof (pfx_node_t*) * node_->count); free (old_table); node_->min = new_min; } else if (c == node_->min + node_->count - 1) { // We can compact the table "from the right". unsigned short new_count = node_->count; for (unsigned short i = 1; i < node_->count; ++i) { if (node_->next.table [node_->count - 1 - i]) { new_count = node_->count - i; break; } } xs_assert (new_count != node_->count); node_->count = new_count; pfx_node_t **old_table = node_->next.table; node_->next.table = (pfx_node_t**) malloc (sizeof (pfx_node_t*) * node_->count); alloc_assert (node_->next.table); memmove (node_->next.table, old_table, sizeof (pfx_node_t*) * node_->count); free (old_table); } } } return ret; }
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 ()) { LIBZMQ_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; }
void zmq::pgm_receiver_t::in_event () { // Read data from the underlying pgm_socket. const pgm_tsi_t *tsi = NULL; if (has_rx_timer) { cancel_timer (rx_timer_id); has_rx_timer = false; } // TODO: This loop can effectively block other engines in the same I/O // thread in the case of high load. while (true) { // Get new batch of data. // Note the workaround made not to break strict-aliasing rules. void *tmp = NULL; ssize_t received = pgm_socket.receive (&tmp, &tsi); inpos = (unsigned char*) tmp; // No data to process. This may happen if the packet received is // neither ODATA nor ODATA. if (received == 0) { if (errno == ENOMEM || errno == EBUSY) { const long timeout = pgm_socket.get_rx_timeout (); add_timer (timeout, rx_timer_id); has_rx_timer = true; } break; } // Find the peer based on its TSI. peers_t::iterator it = peers.find (*tsi); // Data loss. Delete decoder and mark the peer as disjoint. if (received == -1) { if (it != peers.end ()) { it->second.joined = false; if (it->second.decoder != NULL) { LIBZMQ_DELETE(it->second.decoder); } } break; } // New peer. Add it to the list of know but unjoint peers. if (it == peers.end ()) { peer_info_t peer_info = {false, NULL}; it = peers.insert (peers_t::value_type (*tsi, peer_info)).first; } insize = static_cast <size_t> (received); // Read the offset of the fist message in the current packet. zmq_assert (insize >= sizeof (uint16_t)); uint16_t offset = get_uint16 (inpos); inpos += sizeof (uint16_t); insize -= sizeof (uint16_t); // Join the stream if needed. if (!it->second.joined) { // There is no beginning of the message in current packet. // Ignore the data. if (offset == 0xffff) continue; zmq_assert (offset <= insize); zmq_assert (it->second.decoder == NULL); // We have to move data to the beginning of the first message. inpos += offset; insize -= offset; // Mark the stream as joined. it->second.joined = true; // Create and connect decoder for the peer. it->second.decoder = new (std::nothrow) v1_decoder_t (0, options.maxmsgsize); alloc_assert (it->second.decoder); } int rc = process_input (it->second.decoder); if (rc == -1) { if (errno == EAGAIN) { active_tsi = tsi; // Stop polling. reset_pollin (pipe_handle); reset_pollin (socket_handle); break; } it->second.joined = false; LIBZMQ_DELETE(it->second.decoder); insize = 0; } } // Flush any messages decoder may have produced. session->flush (); }
void *zmq_poller_new (void) { zmq::socket_poller_t *poller = new (std::nothrow) zmq::socket_poller_t; alloc_assert (poller); return poller; }
void zmq::socket_base_t::copy_monitor_address (char *dest_, std::string &src_) { alloc_assert (dest_); dest_[src_.size ()] = 0; memcpy (dest_, src_.c_str (), src_.size ()); }
int zmq::socket_base_t::connect (const char *addr_) { if (unlikely (ctx_terminated)) { errno = ETERM; return -1; } // Process pending commands, if any. int rc = process_commands (0, false); if (unlikely (rc != 0)) return -1; // Parse addr_ string. std::string protocol; std::string address; rc = parse_uri (addr_, protocol, address); if (rc != 0) return -1; rc = check_protocol (protocol); if (rc != 0) return -1; if (protocol == "inproc") { // TODO: inproc connect is specific with respect to creating pipes // as there's no 'reconnect' functionality implemented. Once that // is in place we should follow generic pipe creation algorithm. // Find the peer endpoint. endpoint_t peer = find_endpoint (addr_); if (!peer.socket) return -1; // The total HWM for an inproc connection should be the sum of // the binder's HWM and the connector's HWM. int sndhwm = 0; if (options.sndhwm != 0 && peer.options.rcvhwm != 0) sndhwm = options.sndhwm + peer.options.rcvhwm; int rcvhwm = 0; if (options.rcvhwm != 0 && peer.options.sndhwm != 0) rcvhwm = options.rcvhwm + peer.options.sndhwm; // Create a bi-directional pipe to connect the peers. object_t *parents [2] = {this, peer.socket}; pipe_t *pipes [2] = {NULL, NULL}; int hwms [2] = {sndhwm, rcvhwm}; bool delays [2] = {options.delay_on_disconnect, options.delay_on_close}; int rc = pipepair (parents, pipes, hwms, delays); errno_assert (rc == 0); // Attach local end of the pipe to this socket object. attach_pipe (pipes [0]); // If required, send the identity of the local socket to the peer. if (peer.options.recv_identity) { msg_t id; rc = id.init_size (options.identity_size); errno_assert (rc == 0); memcpy (id.data (), options.identity, options.identity_size); id.set_flags (msg_t::identity); bool written = pipes [0]->write (&id); zmq_assert (written); pipes [0]->flush (); } // If required, send the identity of the peer to the local socket. if (options.recv_identity) { msg_t id; rc = id.init_size (peer.options.identity_size); errno_assert (rc == 0); memcpy (id.data (), peer.options.identity, peer.options.identity_size); id.set_flags (msg_t::identity); bool written = pipes [1]->write (&id); zmq_assert (written); pipes [1]->flush (); } // Attach remote end of the pipe to the peer socket. Note that peer's // seqnum was incremented in find_endpoint function. We don't need it // increased here. send_bind (peer.socket, pipes [1], false); // Save last endpoint URI options.last_endpoint.assign (addr_); // remember inproc connections for disconnect inprocs.insert (inprocs_t::value_type (std::string (addr_), pipes[0])); return 0; } // Choose the I/O thread to run the session in. io_thread_t *io_thread = choose_io_thread (options.affinity); if (!io_thread) { errno = EMTHREAD; return -1; } address_t *paddr = new (std::nothrow) address_t (protocol, address); alloc_assert (paddr); // Resolve address (if needed by the protocol) if (protocol == "tcp") { paddr->resolved.tcp_addr = new (std::nothrow) tcp_address_t (); alloc_assert (paddr->resolved.tcp_addr); int rc = paddr->resolved.tcp_addr->resolve ( address.c_str (), false, options.ipv4only ? true : false); if (rc != 0) { delete paddr; return -1; } } #if !defined ZMQ_HAVE_WINDOWS && !defined ZMQ_HAVE_OPENVMS else if (protocol == "ipc") { paddr->resolved.ipc_addr = new (std::nothrow) ipc_address_t (); alloc_assert (paddr->resolved.ipc_addr); int rc = paddr->resolved.ipc_addr->resolve (address.c_str ()); if (rc != 0) { delete paddr; return -1; } } #endif #ifdef ZMQ_HAVE_OPENPGM if (protocol == "pgm" || protocol == "epgm") { struct pgm_addrinfo_t *res = NULL; uint16_t port_number = 0; int rc = pgm_socket_t::init_address(address.c_str(), &res, &port_number); if (res != NULL) pgm_freeaddrinfo (res); if (rc != 0 || port_number == 0) return -1; } #endif // Create session. session_base_t *session = session_base_t::create (io_thread, true, this, options, paddr); errno_assert (session); // PGM does not support subscription forwarding; ask for all data to be // sent to this pipe. bool icanhasall = protocol == "pgm" || protocol == "epgm"; if (options.delay_attach_on_connect != 1 || icanhasall) { // Create a bi-directional pipe. object_t *parents [2] = {this, session}; pipe_t *pipes [2] = {NULL, NULL}; int hwms [2] = {options.sndhwm, options.rcvhwm}; bool delays [2] = {options.delay_on_disconnect, options.delay_on_close}; rc = pipepair (parents, pipes, hwms, delays); errno_assert (rc == 0); // Attach local end of the pipe to the socket object. attach_pipe (pipes [0], icanhasall); // Attach remote end of the pipe to the session object later on. session->attach_pipe (pipes [1]); } // Save last endpoint URI paddr->to_string (options.last_endpoint); add_endpoint (addr_, (own_t *) session); return 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; }
int zmq::socket_base_t::term_endpoint (const char *addr_) { scoped_optional_lock_t sync_lock(thread_safe ? &sync : NULL); // Check whether the library haven't been shut down yet. if (unlikely (ctx_terminated)) { errno = ETERM; return -1; } // Check whether endpoint address passed to the function is valid. if (unlikely (!addr_)) { errno = EINVAL; return -1; } // Process pending commands, if any, since there could be pending unprocessed process_own()'s // (from launch_child() for example) we're asked to terminate now. int rc = process_commands (0, false); if (unlikely(rc != 0)) { return -1; } // Parse addr_ string. std::string protocol; std::string address; if (parse_uri(addr_, protocol, address) || check_protocol(protocol)) { return -1; } // Disconnect an inproc socket if (protocol == "inproc") { if (unregister_endpoint (std::string(addr_), this) == 0) { return 0; } std::pair <inprocs_t::iterator, inprocs_t::iterator> range = inprocs.equal_range (std::string (addr_)); if (range.first == range.second) { errno = ENOENT; return -1; } for (inprocs_t::iterator it = range.first; it != range.second; ++it) it->second->terminate (true); inprocs.erase (range.first, range.second); return 0; } std::string resolved_addr = std::string (addr_); std::pair <endpoints_t::iterator, endpoints_t::iterator> range; // The resolved last_endpoint is used as a key in the endpoints map. // The address passed by the user might not match in the TCP case due to // IPv4-in-IPv6 mapping (EG: tcp://[::ffff:127.0.0.1]:9999), so try to // resolve before giving up. Given at this stage we don't know whether a // socket is connected or bound, try with both. if (protocol == "tcp") { range = endpoints.equal_range (resolved_addr); if (range.first == range.second) { tcp_address_t *tcp_addr = new (std::nothrow) tcp_address_t (); alloc_assert (tcp_addr); rc = tcp_addr->resolve (address.c_str (), false, options.ipv6); if (rc == 0) { tcp_addr->to_string (resolved_addr); range = endpoints.equal_range (resolved_addr); if (range.first == range.second) { rc = tcp_addr->resolve (address.c_str (), true, options.ipv6); if (rc == 0) { tcp_addr->to_string (resolved_addr); } } } LIBZMQ_DELETE(tcp_addr); } } // Find the endpoints range (if any) corresponding to the addr_ string. range = endpoints.equal_range (resolved_addr); if (range.first == range.second) { errno = ENOENT; return -1; } for (endpoints_t::iterator it = range.first; it != range.second; ++it) { // If we have an associated pipe, terminate it. if (it->second.second != NULL) it->second.second->terminate (false); term_child (it->second.first); } endpoints.erase (range.first, range.second); return 0; }
int zmq::socket_base_t::bind (const char *addr_) { scoped_optional_lock_t sync_lock(thread_safe ? &sync : NULL); if (unlikely (ctx_terminated)) { errno = ETERM; return -1; } // Process pending commands, if any. int rc = process_commands (0, false); if (unlikely (rc != 0)) { return -1; } // Parse addr_ string. std::string protocol; std::string address; if (parse_uri (addr_, protocol, address) || check_protocol (protocol)) { return -1; } if (protocol == "inproc") { const endpoint_t endpoint = { this, options }; rc = register_endpoint (addr_, endpoint); if (rc == 0) { connect_pending (addr_, this); last_endpoint.assign (addr_); options.connected = true; } return rc; } if (protocol == "pgm" || protocol == "epgm" || protocol == "norm") { // For convenience's sake, bind can be used interchangeable with // connect for PGM, EPGM, NORM transports. rc = connect (addr_); if (rc != -1) options.connected = true; return rc; } if (protocol == "udp") { if (!(options.type == ZMQ_DGRAM || options.type == ZMQ_DISH)) { errno = ENOCOMPATPROTO; return -1; } // Choose the I/O thread to run the session in. io_thread_t *io_thread = choose_io_thread (options.affinity); if (!io_thread) { errno = EMTHREAD; return -1; } address_t *paddr = new (std::nothrow) address_t (protocol, address, this->get_ctx ()); alloc_assert (paddr); paddr->resolved.udp_addr = new (std::nothrow) udp_address_t (); alloc_assert (paddr->resolved.udp_addr); rc = paddr->resolved.udp_addr->resolve (address.c_str(), true); if (rc != 0) { LIBZMQ_DELETE(paddr); return -1; } session_base_t *session = session_base_t::create (io_thread, true, this, options, paddr); errno_assert (session); pipe_t *newpipe = NULL; // Create a bi-directional pipe. object_t *parents [2] = {this, session}; pipe_t *new_pipes [2] = {NULL, NULL}; int hwms [2] = {options.sndhwm, options.rcvhwm}; bool conflates [2] = {false, false}; rc = pipepair (parents, new_pipes, hwms, conflates); errno_assert (rc == 0); // Attach local end of the pipe to the socket object. attach_pipe (new_pipes [0], true); newpipe = new_pipes [0]; // Attach remote end of the pipe to the session object later on. session->attach_pipe (new_pipes [1]); // Save last endpoint URI paddr->to_string (last_endpoint); add_endpoint (addr_, (own_t *) session, newpipe); return 0; } // Remaining transports require to be run in an I/O thread, so at this // point we'll choose one. io_thread_t *io_thread = choose_io_thread (options.affinity); if (!io_thread) { errno = EMTHREAD; return -1; } if (protocol == "tcp") { tcp_listener_t *listener = new (std::nothrow) tcp_listener_t ( io_thread, this, options); alloc_assert (listener); rc = listener->set_address (address.c_str ()); if (rc != 0) { LIBZMQ_DELETE(listener); event_bind_failed (address, zmq_errno()); return -1; } // Save last endpoint URI listener->get_address (last_endpoint); add_endpoint (last_endpoint.c_str (), (own_t *) listener, NULL); options.connected = true; return 0; } #if !defined ZMQ_HAVE_WINDOWS && !defined ZMQ_HAVE_OPENVMS if (protocol == "ipc") { ipc_listener_t *listener = new (std::nothrow) ipc_listener_t ( io_thread, this, options); alloc_assert (listener); int rc = listener->set_address (address.c_str ()); if (rc != 0) { LIBZMQ_DELETE(listener); event_bind_failed (address, zmq_errno()); return -1; } // Save last endpoint URI listener->get_address (last_endpoint); add_endpoint (last_endpoint.c_str (), (own_t *) listener, NULL); options.connected = true; return 0; } #endif #if defined ZMQ_HAVE_TIPC if (protocol == "tipc") { tipc_listener_t *listener = new (std::nothrow) tipc_listener_t ( io_thread, this, options); alloc_assert (listener); int rc = listener->set_address (address.c_str ()); if (rc != 0) { LIBZMQ_DELETE(listener); event_bind_failed (address, zmq_errno()); return -1; } // Save last endpoint URI listener->get_address (last_endpoint); add_endpoint (addr_, (own_t *) listener, NULL); options.connected = true; return 0; } #endif #if defined ZMQ_HAVE_VMCI if (protocol == "vmci") { vmci_listener_t *listener = new (std::nothrow) vmci_listener_t ( io_thread, this, options); alloc_assert (listener); int rc = listener->set_address (address.c_str ()); if (rc != 0) { LIBZMQ_DELETE(listener); event_bind_failed (address, zmq_errno ()); return -1; } listener->get_address (last_endpoint); add_endpoint (last_endpoint.c_str(), (own_t *) listener, NULL); options.connected = true; return 0; } #endif zmq_assert (false); return -1; }
static void nn_ctx_init (void) { int i; #if defined NN_HAVE_WINDOWS WSADATA data; int rc; #endif /* Check whether the library was already initialised. If so, do nothing. */ if (self.socks) return; /* On Windows, initialise the socket library. */ #if defined NN_HAVE_WINDOWS rc = WSAStartup (MAKEWORD (2, 2), &data); nn_assert (rc == 0); nn_assert (LOBYTE (data.wVersion) == 2 && HIBYTE (data.wVersion) == 2); #endif /* Initialise the memory allocation subsystem. */ nn_alloc_init (); /* Seed the pseudo-random number generator. */ nn_random_seed (); /* Allocate the global table of SP sockets. */ self.socks = nn_alloc ((sizeof (struct nn_sock*) * NN_MAX_SOCKETS) + (sizeof (uint16_t) * NN_MAX_SOCKETS), "socket table"); alloc_assert (self.socks); for (i = 0; i != NN_MAX_SOCKETS; ++i) self.socks [i] = NULL; self.nsocks = 0; self.flags = 0; /* Allocate the stack of unused file descriptors. */ self.unused = (uint16_t*) (self.socks + NN_MAX_SOCKETS); alloc_assert (self.unused); for (i = 0; i != NN_MAX_SOCKETS; ++i) self.unused [i] = NN_MAX_SOCKETS - i - 1; /* Initialise other parts of the global state. */ nn_list_init (&self.transports); nn_list_init (&self.socktypes); /* Plug in individual transports. */ nn_ctx_add_transport (nn_inproc); #if !defined NN_HAVE_WINDOWS nn_ctx_add_transport (nn_ipc); #endif nn_ctx_add_transport (nn_tcp); /* Plug in individual socktypes. */ nn_ctx_add_socktype (nn_pair_socktype); nn_ctx_add_socktype (nn_xpair_socktype); nn_ctx_add_socktype (nn_pub_socktype); nn_ctx_add_socktype (nn_sub_socktype); nn_ctx_add_socktype (nn_rep_socktype); nn_ctx_add_socktype (nn_req_socktype); nn_ctx_add_socktype (nn_xrep_socktype); nn_ctx_add_socktype (nn_xreq_socktype); nn_ctx_add_socktype (nn_sink_socktype); nn_ctx_add_socktype (nn_source_socktype); nn_ctx_add_socktype (nn_xsink_socktype); nn_ctx_add_socktype (nn_xsource_socktype); nn_ctx_add_socktype (nn_push_socktype); nn_ctx_add_socktype (nn_xpush_socktype); nn_ctx_add_socktype (nn_pull_socktype); nn_ctx_add_socktype (nn_xpull_socktype); nn_ctx_add_socktype (nn_respondent_socktype); nn_ctx_add_socktype (nn_surveyor_socktype); nn_ctx_add_socktype (nn_xrespondent_socktype); nn_ctx_add_socktype (nn_xsurveyor_socktype); nn_ctx_add_socktype (nn_bus_socktype); nn_ctx_add_socktype (nn_xbus_socktype); #if defined NN_LATENCY_MONITOR nn_latmon_init (); #endif }
void *zmq_timers_new (void) { zmq::timers_t *timers = new (std::nothrow) zmq::timers_t; alloc_assert (timers); return timers; }
static void pfx_rm_all (pfx_node_t *node_, void *subscribers_, unsigned char **buff_, size_t buffsize_, size_t maxbuffsize_, void *arg_) { // Remove the subscription from this node. if (node_->subscribers) { pfx_node_t::subscribers_t::iterator it = node_->subscribers->find (subscribers_); if (it != node_->subscribers->end ()) { xs_assert (it->second); --it->second; if (!it->second) { node_->subscribers->erase (it); if (node_->subscribers->empty ()) { int rc = xs_filter_unsubscribed (arg_, *buff_, buffsize_); errno_assert (rc == 0); delete node_->subscribers; node_->subscribers = 0; } } } } // 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 (node_->count == 0) return; // If there's one subnode (optimisation). if (node_->count == 1) { (*buff_) [buffsize_] = node_->min; buffsize_++; pfx_rm_all (node_->next.node, subscribers_, buff_, buffsize_, maxbuffsize_, arg_); // Prune the node if it was made redundant by the removal if (pfx_is_redundant (node_->next.node)) { pfx_close (node_->next.node); free (node_->next.node); node_->next.node = 0; node_->count = 0; --node_->live_nodes; xs_assert (node_->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 = node_->min + node_->count - 1; // New max non-null character in the node table after the removal. unsigned char new_max = node_->min; for (unsigned short c = 0; c != node_->count; c++) { (*buff_) [buffsize_] = node_->min + c; if (node_->next.table [c]) { pfx_rm_all (node_->next.table [c], subscribers_, buff_, buffsize_ + 1, maxbuffsize_, arg_); // Prune redundant nodes from the the trie. if (pfx_is_redundant (node_->next.table [c])) { pfx_close (node_->next.table [c]); free (node_->next.table [c]); node_->next.table [c] = 0; xs_assert (node_->live_nodes > 0); --node_->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 + node_->min < new_min) new_min = c + node_->min; if (c + node_->min > new_max) new_max = c + node_->min; } } } xs_assert (node_->count > 1); // Compact the node table if possible. if (node_->live_nodes == 0) { // Free the node table if it's no longer used. free (node_->next.table); node_->next.table = NULL; node_->count = 0; } else if (node_->live_nodes == 1) { // If there's only one live node in the table we can // switch to using the more compact single-node // representation. xs_assert (new_min == new_max); xs_assert (new_min >= node_->min && new_min < node_->min + node_->count); pfx_node_t *node = node_->next.table [new_min - node_->min]; xs_assert (node); free (node_->next.table); node_->next.node = node; node_->count = 1; node_->min = new_min; } else if (new_min > node_->min || new_max < node_->min + node_->count - 1) { xs_assert (new_max - new_min + 1 > 1); pfx_node_t **old_table = node_->next.table; xs_assert (new_min > node_->min || new_max < node_->min + node_->count - 1); xs_assert (new_min >= node_->min); xs_assert (new_max <= node_->min + node_->count - 1); xs_assert (new_max - new_min + 1 < node_->count); node_->count = new_max - new_min + 1; node_->next.table = (pfx_node_t**) malloc (sizeof (pfx_node_t*) * node_->count); alloc_assert (node_->next.table); memmove (node_->next.table, old_table + (new_min - node_->min), sizeof (pfx_node_t*) * node_->count); free (old_table); node_->min = new_min; } }
int zmq_poll (zmq_pollitem_t *items_, int nitems_, long timeout_) { // TODO: the function implementation can just call zmq_pollfd_poll with // pollfd as NULL, however pollfd is not yet stable. #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) | (items_ [i].events & ZMQ_POLLPRI ? POLLPRI : 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 & POLLPRI) items_ [i].revents |= ZMQ_POLLPRI; if (pollfds [i].revents & ~(POLLIN | POLLOUT | POLLPRI)) items_ [i].revents |= ZMQ_POLLERR; } if (items_ [i].revents) nevents++; } // If timeout 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 = { 0 }; fd_set pollset_out = { 0 }; fd_set pollset_err = { 0 }; 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 timeout 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 }
static bool pfx_add (pfx_node_t *node_, const unsigned char *prefix_, size_t size_, void *subscriber_) { // We are at the node corresponding to the prefix. We are done. if (!size_) { bool result = !node_->subscribers; if (!node_->subscribers) node_->subscribers = new (std::nothrow) pfx_node_t::subscribers_t; pfx_node_t::subscribers_t::iterator it = node_->subscribers->insert ( pfx_node_t::subscribers_t::value_type (subscriber_, 0)).first; ++it->second; return result; } unsigned char c = *prefix_; if (c < node_->min || c >= node_->min + node_->count) { // The character is out of range of currently handled // charcters. We have to extend the table. if (!node_->count) { node_->min = c; node_->count = 1; node_->next.node = NULL; } else if (node_->count == 1) { unsigned char oldc = node_->min; pfx_node_t *oldp = node_->next.node; node_->count = (node_->min < c ? c - node_->min : node_->min - c) + 1; node_->next.table = (pfx_node_t**) malloc (sizeof (pfx_node_t*) * node_->count); alloc_assert (node_->next.table); for (unsigned short i = 0; i != node_->count; ++i) node_->next.table [i] = 0; node_->min = std::min (node_->min, c); node_->next.table [oldc - node_->min] = oldp; } else if (node_->min < c) { // The new character is above the current character range. unsigned short old_count = node_->count; node_->count = c - node_->min + 1; node_->next.table = (pfx_node_t**) realloc ((void*) node_->next.table, sizeof (pfx_node_t*) * node_->count); xs_assert (node_->next.table); for (unsigned short i = old_count; i != node_->count; i++) node_->next.table [i] = NULL; } else { // The new character is below the current character range. unsigned short old_count = node_->count; node_->count = (node_->min + old_count) - c; node_->next.table = (pfx_node_t**) realloc ((void*) node_->next.table, sizeof (pfx_node_t*) * node_->count); xs_assert (node_->next.table); memmove (node_->next.table + node_->min - c, node_->next.table, old_count * sizeof (pfx_node_t*)); for (unsigned short i = 0; i != node_->min - c; i++) node_->next.table [i] = NULL; node_->min = c; } } // If next node does not exist, create one. if (node_->count == 1) { if (!node_->next.node) { node_->next.node = (pfx_node_t*) malloc (sizeof (pfx_node_t)); alloc_assert (node_->next.node); pfx_init (node_->next.node); ++node_->live_nodes; xs_assert (node_->next.node); } return pfx_add (node_->next.node, prefix_ + 1, size_ - 1, subscriber_); } else { if (!node_->next.table [c - node_->min]) { node_->next.table [c - node_->min] = (pfx_node_t*) malloc (sizeof (pfx_node_t)); alloc_assert (node_->next.table [c - node_->min]); pfx_init (node_->next.table [c - node_->min]); ++node_->live_nodes; xs_assert (node_->next.table [c - node_->min]); } return pfx_add (node_->next.table [c - node_->min], prefix_ + 1, size_ - 1, subscriber_); } }
int zmq::socket_base_t::bind (const char *addr_) { ENTER_MUTEX(); if (unlikely (ctx_terminated)) { errno = ETERM; EXIT_MUTEX(); return -1; } // Process pending commands, if any. int rc = process_commands (0, false); if (unlikely (rc != 0)) { EXIT_MUTEX(); return -1; } // Parse addr_ string. std::string protocol; std::string address; if (parse_uri (addr_, protocol, address) || check_protocol (protocol)) { EXIT_MUTEX(); return -1; } if (protocol == "inproc") { const endpoint_t endpoint = { this, options }; const int rc = register_endpoint (addr_, endpoint); if (rc == 0) { connect_pending (addr_, this); last_endpoint.assign (addr_); } EXIT_MUTEX(); return rc; } if (protocol == "pgm" || protocol == "epgm" || protocol == "norm") { // For convenience's sake, bind can be used interchageable with // connect for PGM, EPGM and NORM transports. EXIT_MUTEX(); return connect (addr_); } // Remaining trasnports require to be run in an I/O thread, so at this // point we'll choose one. io_thread_t *io_thread = choose_io_thread (options.affinity); if (!io_thread) { errno = EMTHREAD; EXIT_MUTEX(); return -1; } if (protocol == "tcp") { tcp_listener_t *listener = new (std::nothrow) tcp_listener_t ( io_thread, this, options); alloc_assert (listener); int rc = listener->set_address (address.c_str ()); if (rc != 0) { delete listener; event_bind_failed (address, zmq_errno()); EXIT_MUTEX(); return -1; } // Save last endpoint URI listener->get_address (last_endpoint); add_endpoint (last_endpoint.c_str (), (own_t *) listener, NULL); EXIT_MUTEX(); return 0; } #if !defined ZMQ_HAVE_WINDOWS && !defined ZMQ_HAVE_OPENVMS if (protocol == "ipc") { ipc_listener_t *listener = new (std::nothrow) ipc_listener_t ( io_thread, this, options); alloc_assert (listener); int rc = listener->set_address (address.c_str ()); if (rc != 0) { delete listener; event_bind_failed (address, zmq_errno()); EXIT_MUTEX(); return -1; } // Save last endpoint URI listener->get_address (last_endpoint); add_endpoint (last_endpoint.c_str (), (own_t *) listener, NULL); EXIT_MUTEX(); return 0; } #endif #if defined ZMQ_HAVE_TIPC if (protocol == "tipc") { tipc_listener_t *listener = new (std::nothrow) tipc_listener_t ( io_thread, this, options); alloc_assert (listener); int rc = listener->set_address (address.c_str ()); if (rc != 0) { delete listener; event_bind_failed (address, zmq_errno()); EXIT_MUTEX(); return -1; } // Save last endpoint URI listener->get_address (last_endpoint); add_endpoint (addr_, (own_t *) listener, NULL); EXIT_MUTEX(); return 0; } #endif EXIT_MUTEX(); zmq_assert (false); return -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 = read (greeting_recv + greeting_bytes_read, greeting_size - greeting_bytes_read); if (n == 0) { error (); return false; } if (n == -1) { if (errno != EAGAIN) 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); if (options.mechanism == ZMQ_NULL) memcpy (outpos + outsize, "NULL", 4); else if (options.mechanism == ZMQ_PLAIN) memcpy (outpos + outsize, "PLAIN", 5); else memcpy (outpos + outsize, "CURVE", 5); outsize += 20; memset (outpos + outsize, 0, 32); outsize += 32; greeting_size = v3_greeting_size; } } } } // Position of the revision field in the greeting. const size_t revision_pos = 10; // Is the peer using ZMTP/1.0 with no revision number? // If so, we send and receive rest of identity message if (greeting_recv [0] != 0xff || !(greeting_recv [9] & 0x01)) { encoder = new (std::nothrow) v1_encoder_t (out_batch_size); alloc_assert (encoder); decoder = new (std::nothrow) v1_decoder_t (in_batch_size, options.maxmsgsize); alloc_assert (decoder); // We have already sent the message header. // Since there is no way to tell the encoder to // skip the message header, we simply throw that // header data away. const size_t header_size = options.identity_size + 1 >= 255 ? 10 : 2; unsigned char tmp [10], *bufferp = tmp; // 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. read_msg = &stream_engine_t::pull_msg_from_session; // We are expecting identity message. write_msg = &stream_engine_t::write_identity; } else if (greeting_recv [revision_pos] == ZMTP_1_0) { encoder = new (std::nothrow) v1_encoder_t ( out_batch_size); alloc_assert (encoder); decoder = new (std::nothrow) v1_decoder_t ( in_batch_size, options.maxmsgsize); alloc_assert (decoder); } else if (greeting_recv [revision_pos] == ZMTP_2_0) { encoder = new (std::nothrow) v2_encoder_t (out_batch_size); alloc_assert (encoder); decoder = new (std::nothrow) v2_decoder_t ( in_batch_size, options.maxmsgsize); alloc_assert (decoder); } else { encoder = new (std::nothrow) v2_encoder_t (out_batch_size); alloc_assert (encoder); decoder = new (std::nothrow) v2_decoder_t ( in_batch_size, options.maxmsgsize); alloc_assert (decoder); if (memcmp (greeting_recv + 12, "NULL\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) == 0) { mechanism = new (std::nothrow) null_mechanism_t (session, peer_address, options); alloc_assert (mechanism); } else if (memcmp (greeting_recv + 12, "PLAIN\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) == 0) { mechanism = new (std::nothrow) plain_mechanism_t (session, peer_address, options); alloc_assert (mechanism); } #ifdef HAVE_LIBSODIUM else if (memcmp (greeting_recv + 12, "CURVE\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) == 0) { if (options.as_server) mechanism = new (std::nothrow) curve_server_t (session, peer_address, options); else mechanism = new (std::nothrow) curve_client_t (options); alloc_assert (mechanism); } #endif else { error (); return false; } read_msg = &stream_engine_t::next_handshake_command; write_msg = &stream_engine_t::process_handshake_command; } // Start polling for output if necessary. if (outsize == 0) set_pollout (handle); // Handshaking was successful. // Switch into the normal message flow. handshaking = false; return true; }
int zmq::socket_base_t::connect (const char *addr_) { ENTER_MUTEX(); if (unlikely (ctx_terminated)) { errno = ETERM; EXIT_MUTEX(); return -1; } // Process pending commands, if any. int rc = process_commands (0, false); if (unlikely (rc != 0)) { EXIT_MUTEX(); return -1; } // Parse addr_ string. std::string protocol; std::string address; if (parse_uri (addr_, protocol, address) || check_protocol (protocol)) { EXIT_MUTEX(); return -1; } if (protocol == "inproc") { // TODO: inproc connect is specific with respect to creating pipes // as there's no 'reconnect' functionality implemented. Once that // is in place we should follow generic pipe creation algorithm. // Find the peer endpoint. endpoint_t peer = find_endpoint (addr_); // The total HWM for an inproc connection should be the sum of // the binder's HWM and the connector's HWM. int sndhwm = 0; if (peer.socket == NULL) sndhwm = options.sndhwm; else if (options.sndhwm != 0 && peer.options.rcvhwm != 0) sndhwm = options.sndhwm + peer.options.rcvhwm; int rcvhwm = 0; if (peer.socket == NULL) rcvhwm = options.rcvhwm; else if (options.rcvhwm != 0 && peer.options.sndhwm != 0) rcvhwm = options.rcvhwm + peer.options.sndhwm; // Create a bi-directional pipe to connect the peers. object_t *parents [2] = {this, peer.socket == NULL ? this : peer.socket}; pipe_t *new_pipes [2] = {NULL, NULL}; bool conflate = options.conflate && (options.type == ZMQ_DEALER || options.type == ZMQ_PULL || options.type == ZMQ_PUSH || options.type == ZMQ_PUB || options.type == ZMQ_SUB); int hwms [2] = {conflate? -1 : sndhwm, conflate? -1 : rcvhwm}; bool conflates [2] = {conflate, conflate}; int rc = pipepair (parents, new_pipes, hwms, conflates); errno_assert (rc == 0); if (!peer.socket) { // The peer doesn't exist yet so we don't know whether // to send the identity message or not. To resolve this, // we always send our identity and drop it later if // the peer doesn't expect it. msg_t id; rc = id.init_size (options.identity_size); errno_assert (rc == 0); memcpy (id.data (), options.identity, options.identity_size); id.set_flags (msg_t::identity); bool written = new_pipes [0]->write (&id); zmq_assert (written); new_pipes [0]->flush (); const endpoint_t endpoint = {this, options}; pend_connection (std::string (addr_), endpoint, new_pipes); } else { // If required, send the identity of the local socket to the peer. if (peer.options.recv_identity) { msg_t id; rc = id.init_size (options.identity_size); errno_assert (rc == 0); memcpy (id.data (), options.identity, options.identity_size); id.set_flags (msg_t::identity); bool written = new_pipes [0]->write (&id); zmq_assert (written); new_pipes [0]->flush (); } // If required, send the identity of the peer to the local socket. if (options.recv_identity) { msg_t id; rc = id.init_size (peer.options.identity_size); errno_assert (rc == 0); memcpy (id.data (), peer.options.identity, peer.options.identity_size); id.set_flags (msg_t::identity); bool written = new_pipes [1]->write (&id); zmq_assert (written); new_pipes [1]->flush (); } // Attach remote end of the pipe to the peer socket. Note that peer's // seqnum was incremented in find_endpoint function. We don't need it // increased here. send_bind (peer.socket, new_pipes [1], false); } // Attach local end of the pipe to this socket object. attach_pipe (new_pipes [0]); // Save last endpoint URI last_endpoint.assign (addr_); // remember inproc connections for disconnect inprocs.insert (inprocs_t::value_type (std::string (addr_), new_pipes [0])); EXIT_MUTEX(); return 0; } bool is_single_connect = (options.type == ZMQ_DEALER || options.type == ZMQ_SUB || options.type == ZMQ_REQ); if (unlikely (is_single_connect)) { const endpoints_t::iterator it = endpoints.find (addr_); if (it != endpoints.end ()) { // There is no valid use for multiple connects for SUB-PUB nor // DEALER-ROUTER nor REQ-REP. Multiple connects produces // nonsensical results. EXIT_MUTEX(); return 0; } } // Choose the I/O thread to run the session in. io_thread_t *io_thread = choose_io_thread (options.affinity); if (!io_thread) { errno = EMTHREAD; EXIT_MUTEX(); return -1; } address_t *paddr = new (std::nothrow) address_t (protocol, address); alloc_assert (paddr); // Resolve address (if needed by the protocol) if (protocol == "tcp") { // Do some basic sanity checks on tcp:// address syntax // - hostname starts with digit or letter, with embedded '-' or '.' // - IPv6 address may contain hex chars and colons. // - IPv4 address may contain decimal digits and dots. // - Address must end in ":port" where port is *, or numeric // - Address may contain two parts separated by ':' // Following code is quick and dirty check to catch obvious errors, // without trying to be fully accurate. const char *check = address.c_str (); if (isalnum (*check) || isxdigit (*check)) { check++; while (isalnum (*check) || isxdigit (*check) || *check == '.' || *check == '-' || *check == ':'|| *check == ';') check++; } // Assume the worst, now look for success rc = -1; // Did we reach the end of the address safely? if (*check == 0) { // Do we have a valid port string? (cannot be '*' in connect check = strrchr (address.c_str (), ':'); if (check) { check++; if (*check && (isdigit (*check))) rc = 0; // Valid } } if (rc == -1) { errno = EINVAL; delete paddr; EXIT_MUTEX(); return -1; } // Defer resolution until a socket is opened paddr->resolved.tcp_addr = NULL; } #if !defined ZMQ_HAVE_WINDOWS && !defined ZMQ_HAVE_OPENVMS else if (protocol == "ipc") { paddr->resolved.ipc_addr = new (std::nothrow) ipc_address_t (); alloc_assert (paddr->resolved.ipc_addr); int rc = paddr->resolved.ipc_addr->resolve (address.c_str ()); if (rc != 0) { delete paddr; EXIT_MUTEX(); return -1; } } #endif // TBD - Should we check address for ZMQ_HAVE_NORM??? #ifdef ZMQ_HAVE_OPENPGM if (protocol == "pgm" || protocol == "epgm") { struct pgm_addrinfo_t *res = NULL; uint16_t port_number = 0; int rc = pgm_socket_t::init_address(address.c_str(), &res, &port_number); if (res != NULL) pgm_freeaddrinfo (res); if (rc != 0 || port_number == 0) EXIT_MUTEX(); return -1; } #endif #if defined ZMQ_HAVE_TIPC else if (protocol == "tipc") { paddr->resolved.tipc_addr = new (std::nothrow) tipc_address_t (); alloc_assert (paddr->resolved.tipc_addr); int rc = paddr->resolved.tipc_addr->resolve (address.c_str()); if (rc != 0) { delete paddr; EXIT_MUTEX(); return -1; } } #endif // Create session. session_base_t *session = session_base_t::create (io_thread, true, this, options, paddr); errno_assert (session); // PGM does not support subscription forwarding; ask for all data to be // sent to this pipe. (same for NORM, currently?) bool subscribe_to_all = protocol == "pgm" || protocol == "epgm" || protocol == "norm"; pipe_t *newpipe = NULL; if (options.immediate != 1 || subscribe_to_all) { // Create a bi-directional pipe. object_t *parents [2] = {this, session}; pipe_t *new_pipes [2] = {NULL, NULL}; bool conflate = options.conflate && (options.type == ZMQ_DEALER || options.type == ZMQ_PULL || options.type == ZMQ_PUSH || options.type == ZMQ_PUB || options.type == ZMQ_SUB); int hwms [2] = {conflate? -1 : options.sndhwm, conflate? -1 : options.rcvhwm}; bool conflates [2] = {conflate, conflate}; rc = pipepair (parents, new_pipes, hwms, conflates); errno_assert (rc == 0); // Attach local end of the pipe to the socket object. attach_pipe (new_pipes [0], subscribe_to_all); newpipe = new_pipes [0]; // Attach remote end of the pipe to the session object later on. session->attach_pipe (new_pipes [1]); } // Save last endpoint URI paddr->to_string (last_endpoint); add_endpoint (addr_, (own_t *) session, newpipe); EXIT_MUTEX(); return 0; }
bool zmq::mtrie_t::rm_helper (unsigned char *prefix_, size_t size_, pipe_t *pipe_) { if (!size_) { if (pipes) { pipes_t::size_type erased = pipes->erase (pipe_); zmq_assert (erased == 1); if (pipes->empty ()) { LIBZMQ_DELETE(pipes); } } return !pipes; } unsigned char c = *prefix_; if (!count || c < min || c >= min + count) return false; mtrie_t *next_node = count == 1 ? next.node : next.table [c - min]; if (!next_node) return false; bool 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; 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; mtrie_t **old_table = next.table; next.table = (mtrie_t**) malloc (sizeof (mtrie_t*) * count); alloc_assert (next.table); memmove (next.table, old_table + i, sizeof (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; mtrie_t **old_table = next.table; next.table = (mtrie_t**) malloc (sizeof (mtrie_t*) * count); alloc_assert (next.table); memmove (next.table, old_table, sizeof (mtrie_t*) * count); free (old_table); } } } return ret; }
zmq::socket_base_t *zmq::socket_base_t::create (int type_, class ctx_t *parent_, uint32_t tid_, int sid_) { socket_base_t *s = NULL; switch (type_) { case ZMQ_PAIR: s = new (std::nothrow) pair_t (parent_, tid_, sid_); break; case ZMQ_PUB: s = new (std::nothrow) pub_t (parent_, tid_, sid_); break; case ZMQ_SUB: s = new (std::nothrow) sub_t (parent_, tid_, sid_); break; case ZMQ_REQ: s = new (std::nothrow) req_t (parent_, tid_, sid_); break; case ZMQ_REP: s = new (std::nothrow) rep_t (parent_, tid_, sid_); break; case ZMQ_DEALER: s = new (std::nothrow) dealer_t (parent_, tid_, sid_); break; case ZMQ_ROUTER: s = new (std::nothrow) router_t (parent_, tid_, sid_); break; case ZMQ_PULL: s = new (std::nothrow) pull_t (parent_, tid_, sid_); break; case ZMQ_PUSH: s = new (std::nothrow) push_t (parent_, tid_, sid_); break; case ZMQ_XPUB: s = new (std::nothrow) xpub_t (parent_, tid_, sid_); break; case ZMQ_XSUB: s = new (std::nothrow) xsub_t (parent_, tid_, sid_); break; case ZMQ_STREAM: s = new (std::nothrow) stream_t (parent_, tid_, sid_); break; case ZMQ_SERVER: s = new (std::nothrow) server_t (parent_, tid_, sid_); break; case ZMQ_CLIENT: s = new (std::nothrow) client_t (parent_, tid_, sid_); break; default: errno = EINVAL; return NULL; } alloc_assert (s); mailbox_t *mailbox = dynamic_cast<mailbox_t*> (s->mailbox); if (mailbox != NULL && mailbox->get_fd () == retired_fd) return NULL; return s; }
int zmq::tcp_connecter_t::open () { zmq_assert (s == retired_fd); // Resolve the address if (addr->resolved.tcp_addr != NULL) { LIBZMQ_DELETE(addr->resolved.tcp_addr); } addr->resolved.tcp_addr = new (std::nothrow) tcp_address_t (); alloc_assert (addr->resolved.tcp_addr); int rc = addr->resolved.tcp_addr->resolve ( addr->address.c_str (), false, options.ipv6); if (rc != 0) { LIBZMQ_DELETE(addr->resolved.tcp_addr); return -1; } zmq_assert (addr->resolved.tcp_addr != NULL); tcp_address_t * const tcp_addr = 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) { errno = wsa_error_to_errno (WSAGetLastError ()); 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) 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); #else if (errno == EINTR) errno = EINPROGRESS; #endif return -1; }
void *zmq_atomic_counter_new (void) { zmq::atomic_counter_t *counter = new (std::nothrow) zmq::atomic_counter_t; alloc_assert (counter); return counter; }
void zmq::session_base_t::start_connecting (bool wait_) { zmq_assert (active); // Choose I/O thread to run connecter in. Given that we are already // running in an I/O thread, there must be at least one available. io_thread_t *io_thread = choose_io_thread (options.affinity); zmq_assert (io_thread); // Create the connecter object. if (addr->protocol == "tcp") { if (!options.socks_proxy_address.empty()) { address_t *proxy_address = new (std::nothrow) address_t ("tcp", options.socks_proxy_address, this->get_ctx ()); alloc_assert (proxy_address); socks_connecter_t *connecter = new (std::nothrow) socks_connecter_t ( io_thread, this, options, addr, proxy_address, wait_); alloc_assert (connecter); launch_child (connecter); } else { tcp_connecter_t *connecter = new (std::nothrow) tcp_connecter_t (io_thread, this, options, addr, wait_); alloc_assert (connecter); launch_child (connecter); } return; } #if !defined ZMQ_HAVE_WINDOWS && !defined ZMQ_HAVE_OPENVMS if (addr->protocol == "ipc") { ipc_connecter_t *connecter = new (std::nothrow) ipc_connecter_t ( io_thread, this, options, addr, wait_); alloc_assert (connecter); launch_child (connecter); return; } #endif #if defined ZMQ_HAVE_TIPC if (addr->protocol == "tipc") { tipc_connecter_t *connecter = new (std::nothrow) tipc_connecter_t ( io_thread, this, options, addr, wait_); alloc_assert (connecter); launch_child (connecter); return; } #endif if (addr->protocol == "udp") { zmq_assert (options.type == ZMQ_DISH || options.type == ZMQ_RADIO); udp_engine_t* engine = new (std::nothrow) udp_engine_t (); alloc_assert (engine); bool recv = false; bool send = false; if (options.type == ZMQ_RADIO) { send = true; recv = false; } else if (options.type == ZMQ_DISH) { send = false; recv = true; } int rc = engine->init (addr, send, recv); errno_assert (rc == 0); send_attach (this, engine); return; } #ifdef ZMQ_HAVE_OPENPGM // Both PGM and EPGM transports are using the same infrastructure. if (addr->protocol == "pgm" || addr->protocol == "epgm") { zmq_assert (options.type == ZMQ_PUB || options.type == ZMQ_XPUB || options.type == ZMQ_SUB || options.type == ZMQ_XSUB); // For EPGM transport with UDP encapsulation of PGM is used. bool const udp_encapsulation = addr->protocol == "epgm"; // At this point we'll create message pipes to the session straight // away. There's no point in delaying it as no concept of 'connect' // exists with PGM anyway. if (options.type == ZMQ_PUB || options.type == ZMQ_XPUB) { // PGM sender. pgm_sender_t *pgm_sender = new (std::nothrow) pgm_sender_t ( io_thread, options); alloc_assert (pgm_sender); int rc = pgm_sender->init (udp_encapsulation, addr->address.c_str ()); errno_assert (rc == 0); send_attach (this, pgm_sender); } else { // PGM receiver. pgm_receiver_t *pgm_receiver = new (std::nothrow) pgm_receiver_t ( io_thread, options); alloc_assert (pgm_receiver); int rc = pgm_receiver->init (udp_encapsulation, addr->address.c_str ()); errno_assert (rc == 0); send_attach (this, pgm_receiver); } return; } #endif #ifdef ZMQ_HAVE_NORM if (addr->protocol == "norm") { // At this point we'll create message pipes to the session straight // away. There's no point in delaying it as no concept of 'connect' // exists with NORM anyway. if (options.type == ZMQ_PUB || options.type == ZMQ_XPUB) { // NORM sender. norm_engine_t* norm_sender = new (std::nothrow) norm_engine_t(io_thread, options); alloc_assert (norm_sender); int rc = norm_sender->init (addr->address.c_str (), true, false); errno_assert (rc == 0); send_attach (this, norm_sender); } else { // ZMQ_SUB or ZMQ_XSUB // NORM receiver. norm_engine_t* norm_receiver = new (std::nothrow) norm_engine_t (io_thread, options); alloc_assert (norm_receiver); int rc = norm_receiver->init (addr->address.c_str (), false, true); errno_assert (rc == 0); send_attach (this, norm_receiver); } return; } #endif // ZMQ_HAVE_NORM #if defined ZMQ_HAVE_VMCI if (addr->protocol == "vmci") { vmci_connecter_t *connecter = new (std::nothrow) vmci_connecter_t ( io_thread, this, options, addr, wait_); alloc_assert (connecter); launch_child (connecter); return; } #endif zmq_assert (false); }
int testmsg() { int rc; int sb; int sc; unsigned char *buf1, *buf2; int i; struct nn_iovec iov; struct nn_msghdr hdr; printf("test msg\n"); if ( 1 ) { sb = test_socket (AF_SP, NN_PAIR); test_bind (sb, SOCKET_ADDRESS); sc = test_socket (AF_SP, NN_PAIR); test_connect (sc, SOCKET_ADDRESS); buf1 = nn_allocmsg (256, 0); alloc_assert (buf1); for (i = 0; i != 256; ++i) buf1 [i] = (unsigned char) i; printf("send 256\n"); rc = nn_send (sc, &buf1, NN_MSG, 0); printf("rc.%d\n",rc); errno_assert (rc >= 0); nn_assert (rc == 256); buf2 = NULL; rc = nn_recv (sb, &buf2, NN_MSG, 0); errno_assert (rc >= 0); nn_assert (rc == 256); nn_assert (buf2); for (i = 0; i != 256; ++i) nn_assert (buf2 [i] == (unsigned char) i); rc = nn_freemsg (buf2); errno_assert (rc == 0); buf1 = nn_allocmsg (256, 0); alloc_assert (buf1); for (i = 0; i != 256; ++i) buf1 [i] = (unsigned char) i; iov.iov_base = &buf1; iov.iov_len = NN_MSG; memset (&hdr, 0, sizeof (hdr)); hdr.msg_iov = &iov; hdr.msg_iovlen = 1; rc = nn_sendmsg (sc, &hdr, 0); errno_assert (rc >= 0); nn_assert (rc == 256); buf2 = NULL; iov.iov_base = &buf2; iov.iov_len = NN_MSG; memset (&hdr, 0, sizeof (hdr)); hdr.msg_iov = &iov; hdr.msg_iovlen = 1; rc = nn_recvmsg (sb, &hdr, 0); errno_assert (rc >= 0); nn_assert (rc == 256); nn_assert (buf2); for (i = 0; i != 256; ++i) nn_assert (buf2 [i] == (unsigned char) i); rc = nn_freemsg (buf2); errno_assert (rc == 0); test_close (sc); test_close (sb); } /* Test receiving of large message */ sb = test_socket(AF_SP, NN_PAIR); //printf("test_bind.(%s)\n",SOCKET_ADDRESS_TCP); test_bind(sb,SOCKET_ADDRESS_TCP); sc = test_socket(AF_SP,NN_PAIR); //printf("test_connect.(%s)\n",SOCKET_ADDRESS_TCP); test_connect(sc,SOCKET_ADDRESS_TCP); for (i = 0; i < (int) sizeof (longdata); ++i) longdata[i] = '0' + (i % 10); longdata [sizeof(longdata) - 1] = 0; printf("send longdata.%d\n",(int32_t)sizeof(longdata)); test_send(sb,longdata); printf("recv longdata.%d\n",(int32_t)sizeof(longdata)); rc = nn_recv (sc, &buf2, NN_MSG, 0); errno_assert (rc >= 0); nn_assert (rc == sizeof (longdata) - 1); nn_assert (buf2); for (i = 0; i < (int) sizeof (longdata) - 1; ++i) nn_assert (buf2 [i] == longdata [i]); rc = nn_freemsg (buf2); errno_assert (rc == 0); test_close (sc); test_close (sb); //printf("testmsg completed\n"); return 0; }
zmq::socket_base_t *zmq::ctx_t::create_socket (int type_) { scoped_lock_t locker(slot_sync); if (unlikely (starting)) { starting = false; // Initialise the array of mailboxes. Additional three slots are for // zmq_ctx_term thread and reaper thread. opt_sync.lock (); int mazmq = max_sockets; int ios = io_thread_count; opt_sync.unlock (); slot_count = mazmq + ios + 2; slots = (i_mailbox **) malloc (sizeof (i_mailbox*) * slot_count); alloc_assert (slots); // Initialise the infrastructure for zmq_ctx_term thread. slots [term_tid] = &term_mailbox; // Create the reaper thread. reaper = new (std::nothrow) reaper_t (this, reaper_tid); alloc_assert (reaper); slots [reaper_tid] = reaper->get_mailbox (); reaper->start (); // Create I/O thread objects and launch them. for (int i = 2; i != ios + 2; i++) { io_thread_t *io_thread = new (std::nothrow) io_thread_t (this, i); alloc_assert (io_thread); io_threads.push_back (io_thread); slots [i] = io_thread->get_mailbox (); io_thread->start (); } // In the unused part of the slot array, create a list of empty slots. for (int32_t i = (int32_t) slot_count - 1; i >= (int32_t) ios + 2; i--) { empty_slots.push_back (i); slots [i] = NULL; } } // Once zmq_ctx_term() was called, we can't create new sockets. if (terminating) { errno = ETERM; return NULL; } // If max_sockets limit was reached, return error. if (empty_slots.empty ()) { errno = EMFILE; return NULL; } // Choose a slot for the socket. uint32_t slot = empty_slots.back (); empty_slots.pop_back (); // Generate new unique socket ID. int sid = ((int) max_socket_id.add (1)) + 1; // Create the socket and register its mailbox. socket_base_t *s = socket_base_t::create (type_, this, slot, sid); if (!s) { empty_slots.push_back (slot); return NULL; } sockets.push_back (s); slots [slot] = s->get_mailbox (); return s; }
inline int zmq_poller_poll (zmq_pollitem_t *items_, int nitems_, long timeout_) { // implement zmq_poll on top of zmq_poller int rc; zmq_poller_event_t *events; events = new zmq_poller_event_t[nitems_]; alloc_assert(events); void *poller = zmq_poller_new (); alloc_assert(poller); bool repeat_items = false; // Register sockets with poller for (int i = 0; i < nitems_; i++) { items_[i].revents = 0; bool modify = false; short e = items_[i].events; if (items_[i].socket) { // Poll item is a 0MQ socket. for (int j = 0; j < i; ++j) { // Check for repeat entries if (items_[j].socket == items_[i].socket) { repeat_items = true; modify = true; e |= items_[j].events; } } if (modify) { rc = zmq_poller_modify (poller, items_[i].socket, e); } else { rc = zmq_poller_add (poller, items_[i].socket, NULL, e); } if (rc < 0) { zmq_poller_destroy (&poller); delete [] events; return rc; } } else { // Poll item is a raw file descriptor. for (int j = 0; j < i; ++j) { // Check for repeat entries if (!items_[j].socket && items_[j].fd == items_[i].fd) { repeat_items = true; modify = true; e |= items_[j].events; } } if (modify) { rc = zmq_poller_modify_fd (poller, items_[i].fd, e); } else { rc = zmq_poller_add_fd (poller, items_[i].fd, NULL, e); } if (rc < 0) { zmq_poller_destroy (&poller); delete [] events; return rc; } } } // Wait for events rc = zmq_poller_wait_all (poller, events, nitems_, timeout_); if (rc < 0) { zmq_poller_destroy (&poller); delete [] events; if (zmq_errno() == ETIMEDOUT) { return 0; } return rc; } // Transform poller events into zmq_pollitem events. // items_ contains all items, while events only contains fired events. // If no sockets are repeated (likely), the two are still co-ordered, so step through the items // checking for matches only on the first event. // If there are repeat items, they cannot be assumed to be co-ordered, // so each pollitem must check fired events from the beginning. int j_start = 0, found_events = rc; for (int i = 0; i < nitems_; i++) { for (int j = j_start; j < found_events; ++j) { if ( (items_[i].socket && items_[i].socket == events[j].socket) || (!(items_[i].socket || items_[j].socket) && items_[i].fd == events[j].fd) ) { items_[i].revents = events[j].events & items_[i].events; if (!repeat_items) { // no repeats, we can ignore events we've already seen j_start++; } break; } if (!repeat_items) { // no repeats, never have to look at j > j_start break; } } } // Cleanup zmq_poller_destroy (&poller); delete [] events; return rc; }