int main(int, char**) { setup_test_environment(); void* context = zmq_ctx_new (); void* sockets [2]; int rc = 0; sockets [SERVER] = zmq_socket (context, ZMQ_STREAM); rc = zmq_bind (sockets [SERVER], "tcp://0.0.0.0:6666"); assert (rc == 0); sockets [CLIENT] = zmq_socket (context, ZMQ_STREAM); rc = zmq_connect (sockets [CLIENT], "tcp://localhost:6666"); assert (rc == 0); // wait for connect notification // Server: Grab the 1st frame (peer identity). zmq_msg_t peer_frame; rc = zmq_msg_init (&peer_frame); assert (rc == 0); rc = zmq_msg_recv (&peer_frame, sockets [SERVER], 0); assert (rc != -1); assert(zmq_msg_size (&peer_frame) > 0); assert (has_more (sockets [SERVER])); // Server: Grab the 2nd frame (actual payload). zmq_msg_t data_frame; rc = zmq_msg_init (&data_frame); assert (rc == 0); rc = zmq_msg_recv (&data_frame, sockets [SERVER], 0); assert (rc != -1); assert(zmq_msg_size (&data_frame) == 0); // Client: Grab the 1st frame (peer identity). rc = zmq_msg_init (&peer_frame); assert (rc == 0); rc = zmq_msg_recv (&peer_frame, sockets [CLIENT], 0); assert (rc != -1); assert(zmq_msg_size (&peer_frame) > 0); assert (has_more (sockets [CLIENT])); // Client: Grab the 2nd frame (actual payload). rc = zmq_msg_init (&data_frame); assert (rc == 0); rc = zmq_msg_recv (&data_frame, sockets [CLIENT], 0); assert (rc != -1); assert(zmq_msg_size (&data_frame) == 0); // Send initial message. char blob_data [256]; size_t blob_size = sizeof(blob_data); rc = zmq_getsockopt (sockets [CLIENT], ZMQ_IDENTITY, blob_data, &blob_size); assert (rc != -1); assert(blob_size > 0); zmq_msg_t msg; rc = zmq_msg_init_size (&msg, blob_size); assert (rc == 0); memcpy (zmq_msg_data (&msg), blob_data, blob_size); rc = zmq_msg_send (&msg, sockets [dialog [0].turn], ZMQ_SNDMORE); assert (rc != -1); rc = zmq_msg_close (&msg); assert (rc == 0); rc = zmq_msg_init_size (&msg, strlen(dialog [0].text)); assert (rc == 0); memcpy (zmq_msg_data (&msg), dialog [0].text, strlen(dialog [0].text)); rc = zmq_msg_send (&msg, sockets [dialog [0].turn], ZMQ_SNDMORE); assert (rc != -1); rc = zmq_msg_close (&msg); assert (rc == 0); // TODO: make sure this loop doesn't loop forever if something is wrong // with the test (or the implementation). int step = 0; while (step < steps) { // Wait until something happens. zmq_pollitem_t items [] = { { sockets [SERVER], 0, ZMQ_POLLIN, 0 }, { sockets [CLIENT], 0, ZMQ_POLLIN, 0 }, }; int rc = zmq_poll (items, 2, 100); assert (rc >= 0); printf ("Event received for step %d.\n", step); // Check for data received by the server. if (items [SERVER].revents & ZMQ_POLLIN) { assert (dialog [step].turn == CLIENT); // Grab the 1st frame (peer identity). zmq_msg_t peer_frame; rc = zmq_msg_init (&peer_frame); assert (rc == 0); rc = zmq_msg_recv (&peer_frame, sockets [SERVER], 0); assert (rc != -1); assert(zmq_msg_size (&peer_frame) > 0); assert (has_more (sockets [SERVER])); // Grab the 2nd frame (actual payload). zmq_msg_t data_frame; rc = zmq_msg_init (&data_frame); assert (rc == 0); rc = zmq_msg_recv (&data_frame, sockets [SERVER], 0); assert (rc != -1); // Make sure payload matches what we expect. const char * const data = (const char*)zmq_msg_data (&data_frame); const int size = zmq_msg_size (&data_frame); // 0-length frame is a disconnection notification. The server // should receive it as the last step in the dialogue. if (size == 0) { printf ("server received disconnection notification!\n"); ++step; assert (step == steps); } else { printf ("server received %d bytes.\n", size); fprintf(stderr, "size = %d, len = %ld\n", size, strlen(dialog [step].text)); assert((size_t)size == strlen(dialog [step].text)); int cmp = memcmp(dialog [step].text, data, size); assert (cmp == 0); ++step; assert (step < steps); // Prepare the response. rc = zmq_msg_close (&data_frame); assert (rc == 0); rc = zmq_msg_init_size (&data_frame, strlen (dialog [step].text)); assert (rc == 0); memcpy (zmq_msg_data (&data_frame), dialog [step].text, zmq_msg_size (&data_frame)); // Send the response. printf ("server sending %d bytes.\n", (int)zmq_msg_size (&data_frame)); rc = zmq_msg_send (&peer_frame, sockets [SERVER], ZMQ_SNDMORE); assert (rc != -1); rc = zmq_msg_send (&data_frame, sockets [SERVER], ZMQ_SNDMORE); assert (rc != -1); } // Release resources. rc = zmq_msg_close (&peer_frame); assert (rc == 0); rc = zmq_msg_close (&data_frame); assert (rc == 0); } // Check for data received by the client. if (items [CLIENT].revents & ZMQ_POLLIN) { assert (dialog [step].turn == SERVER); // Grab the 1st frame (peer identity). zmq_msg_t peer_frame; rc = zmq_msg_init (&peer_frame); assert (rc == 0); rc = zmq_msg_recv (&peer_frame, sockets [CLIENT], 0); assert (rc != -1); assert(zmq_msg_size (&peer_frame) > 0); assert (has_more (sockets [CLIENT])); // Grab the 2nd frame (actual payload). zmq_msg_t data_frame; rc = zmq_msg_init (&data_frame); assert (rc == 0); rc = zmq_msg_recv (&data_frame, sockets [CLIENT], 0); assert (rc != -1); assert(zmq_msg_size (&data_frame) > 0); // Make sure payload matches what we expect. const char * const data = (const char*)zmq_msg_data (&data_frame); const int size = zmq_msg_size (&data_frame); fprintf(stderr, "size = %d, len = %ld\n", size, strlen(dialog [step].text)); assert((size_t)size == strlen(dialog [step].text)); int cmp = memcmp(dialog [step].text, data, size); assert (cmp == 0); printf ("client received %d bytes.\n", size); ++step; // Prepare the response (next line in the dialog). assert (step < steps); rc = zmq_msg_close (&data_frame); assert (rc == 0); rc = zmq_msg_init_size (&data_frame, strlen (dialog [step].text)); assert (rc == 0); memcpy (zmq_msg_data (&data_frame), dialog [step].text, zmq_msg_size (&data_frame)); // Send the response. printf ("client sending %d bytes.\n", (int)zmq_msg_size (&data_frame)); rc = zmq_msg_send (&peer_frame, sockets [CLIENT], ZMQ_SNDMORE); assert (rc != -1); rc = zmq_msg_send (&data_frame, sockets [CLIENT], ZMQ_SNDMORE); assert (rc != -1); // Release resources. rc = zmq_msg_close (&peer_frame); assert (rc == 0); rc = zmq_msg_close (&data_frame); assert (rc == 0); } } assert (step == steps); printf ("Done, exiting now.\n"); rc = zmq_close (sockets [CLIENT]); assert (rc == 0); rc = zmq_close (sockets [SERVER]); assert (rc == 0); rc = zmq_ctx_term (context); assert (rc == 0); return 0; }
int main (int, char **) { setup_test_environment (); size_t len = MAX_SOCKET_STRING; char bind_endpoint[MAX_SOCKET_STRING]; char connect_endpoint[MAX_SOCKET_STRING]; void *context = zmq_ctx_new (); void *sockets[2]; int rc = 0; sockets[SERVER] = zmq_socket (context, ZMQ_STREAM); int enabled = 1; rc = zmq_setsockopt (sockets[SERVER], ZMQ_STREAM_NOTIFY, &enabled, sizeof (enabled)); assert (rc == 0); rc = zmq_bind (sockets[SERVER], "tcp://0.0.0.0:*"); assert (rc == 0); rc = zmq_getsockopt (sockets[SERVER], ZMQ_LAST_ENDPOINT, bind_endpoint, &len); assert (rc == 0); // Apparently Windows can't connect to 0.0.0.0. A better fix would be welcome. #ifdef ZMQ_HAVE_WINDOWS sprintf (connect_endpoint, "tcp://127.0.0.1:%s", strrchr (bind_endpoint, ':') + 1); #else strcpy (connect_endpoint, bind_endpoint); #endif sockets[CLIENT] = zmq_socket (context, ZMQ_STREAM); rc = zmq_setsockopt (sockets[CLIENT], ZMQ_STREAM_NOTIFY, &enabled, sizeof (enabled)); assert (rc == 0); rc = zmq_connect (sockets[CLIENT], connect_endpoint); assert (rc == 0); // wait for connect notification // Server: Grab the 1st frame (peer routing id). zmq_msg_t peer_frame; rc = zmq_msg_init (&peer_frame); assert (rc == 0); rc = zmq_msg_recv (&peer_frame, sockets[SERVER], 0); assert (rc != -1); assert (zmq_msg_size (&peer_frame) > 0); assert (has_more (sockets[SERVER])); rc = zmq_msg_close (&peer_frame); assert (rc == 0); // Server: Grab the 2nd frame (actual payload). zmq_msg_t data_frame; rc = zmq_msg_init (&data_frame); assert (rc == 0); rc = zmq_msg_recv (&data_frame, sockets[SERVER], 0); assert (rc != -1); assert (zmq_msg_size (&data_frame) == 0); rc = zmq_msg_close (&data_frame); assert (rc == 0); // Client: Grab the 1st frame (peer routing id). rc = zmq_msg_init (&peer_frame); assert (rc == 0); rc = zmq_msg_recv (&peer_frame, sockets[CLIENT], 0); assert (rc != -1); assert (zmq_msg_size (&peer_frame) > 0); assert (has_more (sockets[CLIENT])); rc = zmq_msg_close (&peer_frame); assert (rc == 0); // Client: Grab the 2nd frame (actual payload). rc = zmq_msg_init (&data_frame); assert (rc == 0); rc = zmq_msg_recv (&data_frame, sockets[CLIENT], 0); assert (rc != -1); assert (zmq_msg_size (&data_frame) == 0); rc = zmq_msg_close (&data_frame); assert (rc == 0); // Send initial message. char blob_data[256]; size_t blob_size = sizeof (blob_data); rc = zmq_getsockopt (sockets[CLIENT], ZMQ_ROUTING_ID, blob_data, &blob_size); assert (rc != -1); assert (blob_size > 0); zmq_msg_t msg; rc = zmq_msg_init_size (&msg, blob_size); assert (rc == 0); memcpy (zmq_msg_data (&msg), blob_data, blob_size); rc = zmq_msg_send (&msg, sockets[dialog[0].turn], ZMQ_SNDMORE); assert (rc != -1); rc = zmq_msg_close (&msg); assert (rc == 0); rc = zmq_msg_init_size (&msg, strlen (dialog[0].text)); assert (rc == 0); memcpy (zmq_msg_data (&msg), dialog[0].text, strlen (dialog[0].text)); rc = zmq_msg_send (&msg, sockets[dialog[0].turn], ZMQ_SNDMORE); assert (rc != -1); rc = zmq_msg_close (&msg); assert (rc == 0); // TODO: make sure this loop doesn't loop forever if something is wrong // with the test (or the implementation). int step = 0; while (step < steps) { // Wait until something happens. zmq_pollitem_t items[] = { {sockets[SERVER], 0, ZMQ_POLLIN, 0}, {sockets[CLIENT], 0, ZMQ_POLLIN, 0}, }; int rc = zmq_poll (items, 2, 100); assert (rc >= 0); // Check for data received by the server. if (items[SERVER].revents & ZMQ_POLLIN) { assert (dialog[step].turn == CLIENT); // Grab the 1st frame (peer routing id). zmq_msg_t peer_frame; rc = zmq_msg_init (&peer_frame); assert (rc == 0); rc = zmq_msg_recv (&peer_frame, sockets[SERVER], 0); assert (rc != -1); assert (zmq_msg_size (&peer_frame) > 0); assert (has_more (sockets[SERVER])); // Grab the 2nd frame (actual payload). zmq_msg_t data_frame; rc = zmq_msg_init (&data_frame); assert (rc == 0); rc = zmq_msg_recv (&data_frame, sockets[SERVER], 0); assert (rc != -1); // Make sure payload matches what we expect. const char *const data = (const char *) zmq_msg_data (&data_frame); const size_t size = zmq_msg_size (&data_frame); // 0-length frame is a disconnection notification. The server // should receive it as the last step in the dialogue. if (size == 0) { ++step; assert (step == steps); } else { assert (size == strlen (dialog[step].text)); int cmp = memcmp (dialog[step].text, data, size); assert (cmp == 0); ++step; assert (step < steps); // Prepare the response. rc = zmq_msg_close (&data_frame); assert (rc == 0); rc = zmq_msg_init_size (&data_frame, strlen (dialog[step].text)); assert (rc == 0); memcpy (zmq_msg_data (&data_frame), dialog[step].text, zmq_msg_size (&data_frame)); // Send the response. rc = zmq_msg_send (&peer_frame, sockets[SERVER], ZMQ_SNDMORE); assert (rc != -1); rc = zmq_msg_send (&data_frame, sockets[SERVER], ZMQ_SNDMORE); assert (rc != -1); } // Release resources. rc = zmq_msg_close (&peer_frame); assert (rc == 0); rc = zmq_msg_close (&data_frame); assert (rc == 0); } // Check for data received by the client. if (items[CLIENT].revents & ZMQ_POLLIN) { assert (dialog[step].turn == SERVER); // Grab the 1st frame (peer routing id). zmq_msg_t peer_frame; rc = zmq_msg_init (&peer_frame); assert (rc == 0); rc = zmq_msg_recv (&peer_frame, sockets[CLIENT], 0); assert (rc != -1); assert (zmq_msg_size (&peer_frame) > 0); assert (has_more (sockets[CLIENT])); // Grab the 2nd frame (actual payload). zmq_msg_t data_frame; rc = zmq_msg_init (&data_frame); assert (rc == 0); rc = zmq_msg_recv (&data_frame, sockets[CLIENT], 0); assert (rc != -1); assert (zmq_msg_size (&data_frame) > 0); // Make sure payload matches what we expect. const char *const data = (const char *) zmq_msg_data (&data_frame); const size_t size = zmq_msg_size (&data_frame); assert (size == strlen (dialog[step].text)); int cmp = memcmp (dialog[step].text, data, size); assert (cmp == 0); ++step; // Prepare the response (next line in the dialog). assert (step < steps); rc = zmq_msg_close (&data_frame); assert (rc == 0); rc = zmq_msg_init_size (&data_frame, strlen (dialog[step].text)); assert (rc == 0); memcpy (zmq_msg_data (&data_frame), dialog[step].text, zmq_msg_size (&data_frame)); // Send the response. rc = zmq_msg_send (&peer_frame, sockets[CLIENT], ZMQ_SNDMORE); assert (rc != -1); rc = zmq_msg_send (&data_frame, sockets[CLIENT], ZMQ_SNDMORE); assert (rc != -1); // Release resources. rc = zmq_msg_close (&peer_frame); assert (rc == 0); rc = zmq_msg_close (&data_frame); assert (rc == 0); } } assert (step == steps); rc = zmq_close (sockets[CLIENT]); assert (rc == 0); rc = zmq_close (sockets[SERVER]); assert (rc == 0); rc = zmq_ctx_term (context); assert (rc == 0); return 0; }
/** * Called by Java's Socket::getLongSockopt(int option). */ JNIEXPORT jlong JNICALL Java_org_zeromq_ZMQ_00024Socket_getLongSockopt (JNIEnv *env, jobject obj, jint option) { switch (option) { #if ZMQ_VERSION >= ZMQ_MAKE_VERSION(3,0,0) case ZMQ_BACKLOG: case ZMQ_MAXMSGSIZE: case ZMQ_SNDHWM: case ZMQ_RCVHWM: case ZMQ_MULTICAST_HOPS: #else case ZMQ_HWM: case ZMQ_SWAP: case ZMQ_MCAST_LOOP: #endif #if ZMQ_VERSION >= ZMQ_MAKE_VERSION(2,2,0) case ZMQ_RCVTIMEO: case ZMQ_SNDTIMEO: #endif #if ZMQ_VERSION >= ZMQ_MAKE_VERSION(2,1,10) case ZMQ_RECONNECT_IVL: case ZMQ_RECONNECT_IVL_MAX: #endif #if ZMQ_VERSION >= ZMQ_MAKE_VERSION(2,1,0) case ZMQ_TYPE: case ZMQ_FD: case ZMQ_EVENTS: case ZMQ_LINGER: #endif #if ZMQ_VERSION >= ZMQ_MAKE_VERSION(3,2,0) case ZMQ_TCP_KEEPALIVE: case ZMQ_TCP_KEEPALIVE_IDLE: case ZMQ_TCP_KEEPALIVE_CNT: case ZMQ_TCP_KEEPALIVE_INTVL: case ZMQ_IPV4ONLY: #endif case ZMQ_AFFINITY: case ZMQ_RATE: case ZMQ_RECOVERY_IVL: case ZMQ_SNDBUF: case ZMQ_RCVBUF: case ZMQ_RCVMORE: { void *s = get_socket (env, obj); jlong ret = 0; int rc = 0; int err = 0; #if ZMQ_VERSION >= ZMQ_MAKE_VERSION(3,2,0) if( (option == ZMQ_TCP_KEEPALIVE) || (option == ZMQ_TCP_KEEPALIVE_IDLE) || (option == ZMQ_TCP_KEEPALIVE_CNT) || (option == ZMQ_TCP_KEEPALIVE_INTVL) || (option == ZMQ_IPV4ONLY) ) { int optval = 0; size_t optvallen = sizeof(optval); rc = zmq_getsockopt (s, option, &optval, &optvallen); ret = (jlong) optval; } else #endif { uint64_t optval = 0; size_t optvallen = sizeof(optval); rc = zmq_getsockopt (s, option, &optval, &optvallen); ret = (jlong) optval; } err = zmq_errno(); if (rc != 0) { raise_exception (env, err); return 0L; } return ret; } default: raise_exception (env, EINVAL); return 0L; } }
void test_stream_2_stream () { void *rbind, *rconn1; int ret; char buff[256]; char msg[] = "hi 1"; const char *bindip = "tcp://127.0.0.1:*"; int disabled = 0; int zero = 0; size_t len = MAX_SOCKET_STRING; char my_endpoint[MAX_SOCKET_STRING]; void *ctx = zmq_ctx_new (); // Set up listener STREAM. rbind = zmq_socket (ctx, ZMQ_STREAM); assert (rbind); ret = zmq_setsockopt (rbind, ZMQ_STREAM_NOTIFY, &disabled, sizeof (disabled)); assert (ret == 0); ret = zmq_setsockopt (rbind, ZMQ_LINGER, &zero, sizeof (zero)); assert (0 == ret); ret = zmq_bind (rbind, bindip); assert (0 == ret); ret = zmq_getsockopt (rbind, ZMQ_LAST_ENDPOINT, my_endpoint, &len); assert (0 == ret); // Set up connection stream. rconn1 = zmq_socket (ctx, ZMQ_STREAM); assert (rconn1); ret = zmq_setsockopt (rconn1, ZMQ_LINGER, &zero, sizeof (zero)); assert (0 == ret); // Do the connection. ret = zmq_setsockopt (rconn1, ZMQ_CONNECT_ROUTING_ID, "conn1", 6); assert (0 == ret); ret = zmq_connect (rconn1, my_endpoint); /* Uncomment to test assert on duplicate routing id. // Test duplicate connect attempt. ret = zmq_setsockopt (rconn1, ZMQ_CONNECT_ROUTING_ID, "conn1", 6); assert (0 == ret); ret = zmq_connect (rconn1, bindip); assert (0 == ret); */ // Send data to the bound stream. ret = zmq_send (rconn1, "conn1", 6, ZMQ_SNDMORE); assert (6 == ret); ret = zmq_send (rconn1, msg, 5, 0); assert (5 == ret); // Accept data on the bound stream. ret = zmq_recv (rbind, buff, 256, 0); assert (ret); assert (0 == buff[0]); ret = zmq_recv (rbind, buff + 128, 128, 0); assert (5 == ret); assert ('h' == buff[128]); // Handle close of the socket. ret = zmq_unbind (rbind, my_endpoint); assert (0 == ret); ret = zmq_close (rbind); assert (0 == ret); ret = zmq_close (rconn1); assert (0 == ret); zmq_ctx_destroy (ctx); }
bool get_routing_id (void *socket, char *data, size_t *size) { int rc = zmq_getsockopt (socket, ZMQ_ROUTING_ID, data, size); return rc == 0; }
int zmq_poll (zmq_pollitem_t *items_, int nitems_, long timeout_) { #if defined ZMQ_HAVE_POLLER // if poller is present, use that if there is at least 1 thread-safe socket, // otherwise fall back to the previous implementation as it's faster. for (int i = 0; i != nitems_; i++) { if (items_[i].socket && as_socket_base_t (items_[i].socket)->is_thread_safe ()) { return zmq_poller_poll (items_, nitems_, timeout_); } } #endif // ZMQ_HAVE_POLLER #if defined ZMQ_POLL_BASED_ON_POLL || 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; #elif defined ZMQ_HAVE_VXWORKS struct timespec ns_; ns_.tv_sec = timeout_ / 1000; ns_.tv_nsec = timeout_ % 1000 * 1000000; return nanosleep (&ns_, 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; #if defined ZMQ_POLL_BASED_ON_POLL zmq::fast_vector_t<pollfd, ZMQ_POLLITEMS_DFLT> pollfds (nitems_); // 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) { 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); } } #else // Ensure we do not attempt to select () on more than FD_SETSIZE // file descriptors. // TODO since this function is called by a client, we could return errno EINVAL/ENOMEM/... here zmq_assert (nitems_ <= FD_SETSIZE); zmq::optimized_fd_set_t pollset_in (nitems_); FD_ZERO (pollset_in.get ()); zmq::optimized_fd_set_t pollset_out (nitems_); FD_ZERO (pollset_out.get ()); zmq::optimized_fd_set_t pollset_err (nitems_); FD_ZERO (pollset_err.get ()); 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.get ()); 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.get ()); if (items_[i].events & ZMQ_POLLOUT) FD_SET (items_[i].fd, pollset_out.get ()); if (items_[i].events & ZMQ_POLLERR) FD_SET (items_[i].fd, pollset_err.get ()); if (maxfd < items_[i].fd) maxfd = items_[i].fd; } } zmq::optimized_fd_set_t inset (nitems_); zmq::optimized_fd_set_t outset (nitems_); zmq::optimized_fd_set_t errset (nitems_); #endif bool first_pass = true; int nevents = 0; while (true) { #if defined ZMQ_POLL_BASED_ON_POLL // Compute the timeout for the subsequent poll. zmq::timeout_t timeout = zmq::compute_timeout (first_pass, timeout_, now, end); // Wait for events. { int rc = poll (&pollfds[0], nitems_, timeout); if (rc == -1 && errno == EINTR) { return -1; } errno_assert (rc >= 0); } // 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 (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++; } #else // 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 = static_cast<long> ((end - now) / 1000); timeout.tv_usec = static_cast<long> ((end - now) % 1000 * 1000); ptimeout = &timeout; } // Wait for events. Ignore interrupts if there's infinite timeout. while (true) { memcpy (inset.get (), pollset_in.get (), zmq::valid_pollset_bytes (*pollset_in.get ())); memcpy (outset.get (), pollset_out.get (), zmq::valid_pollset_bytes (*pollset_out.get ())); memcpy (errset.get (), pollset_err.get (), zmq::valid_pollset_bytes (*pollset_err.get ())); #if defined ZMQ_HAVE_WINDOWS int rc = select (0, inset.get (), outset.get (), errset.get (), 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.get (), outset.get (), errset.get (), 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.get ())) items_[i].revents |= ZMQ_POLLIN; if (FD_ISSET (items_[i].fd, outset.get ())) items_[i].revents |= ZMQ_POLLOUT; if (FD_ISSET (items_[i].fd, errset.get ())) items_[i].revents |= ZMQ_POLLERR; } if (items_[i].revents) nevents++; } #endif // 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 }
void test_router_2_router (bool named_) { void *rbind, *rconn1; int ret; char buff[256]; char msg[] = "hi 1"; const char *bindip = "tcp://127.0.0.1:*"; int zero = 0; size_t len = MAX_SOCKET_STRING; char my_endpoint[MAX_SOCKET_STRING]; void *ctx = zmq_ctx_new (); // Create bind socket. rbind = zmq_socket (ctx, ZMQ_ROUTER); assert (rbind); ret = zmq_setsockopt (rbind, ZMQ_LINGER, &zero, sizeof (zero)); assert (0 == ret); ret = zmq_bind (rbind, bindip); assert (0 == ret); ret = zmq_getsockopt (rbind, ZMQ_LAST_ENDPOINT, my_endpoint, &len); assert (0 == ret); // Create connection socket. rconn1 = zmq_socket (ctx, ZMQ_ROUTER); assert (rconn1); ret = zmq_setsockopt (rconn1, ZMQ_LINGER, &zero, sizeof (zero)); assert (0 == ret); // If we're in named mode, set some identities. if (named_) { ret = zmq_setsockopt (rbind, ZMQ_ROUTING_ID, "X", 1); ret = zmq_setsockopt (rconn1, ZMQ_ROUTING_ID, "Y", 1); } // Make call to connect using a connect_routing_id. ret = zmq_setsockopt (rconn1, ZMQ_CONNECT_ROUTING_ID, "conn1", 6); assert (0 == ret); ret = zmq_connect (rconn1, my_endpoint); assert (0 == ret); /* Uncomment to test assert on duplicate routing id // Test duplicate connect attempt. ret = zmq_setsockopt (rconn1, ZMQ_CONNECT_ROUTING_ID, "conn1", 6); assert (0 == ret); ret = zmq_connect (rconn1, bindip); assert (0 == ret); */ // Send some data. ret = zmq_send (rconn1, "conn1", 6, ZMQ_SNDMORE); assert (6 == ret); ret = zmq_send (rconn1, msg, 5, 0); assert (5 == ret); // Receive the name. ret = zmq_recv (rbind, buff, 256, 0); if (named_) assert (ret && 'Y' == buff[0]); else assert (ret && 0 == buff[0]); // Receive the data. ret = zmq_recv (rbind, buff + 128, 128, 0); assert (5 == ret && 'h' == buff[128]); // Send some data back. if (named_) { ret = zmq_send (rbind, buff, 1, ZMQ_SNDMORE); assert (1 == ret); } else { ret = zmq_send (rbind, buff, 5, ZMQ_SNDMORE); assert (5 == ret); } ret = zmq_send_const (rbind, "ok", 3, 0); assert (3 == ret); // If bound socket identity naming a problem, we'll likely see something funky here. ret = zmq_recv (rconn1, buff, 256, 0); assert ('c' == buff[0] && 6 == ret); ret = zmq_recv (rconn1, buff + 128, 128, 0); assert (3 == ret && 'o' == buff[128]); ret = zmq_unbind (rbind, my_endpoint); assert (0 == ret); ret = zmq_close (rbind); assert (0 == ret); ret = zmq_close (rconn1); assert (0 == ret); zmq_ctx_destroy (ctx); }
int main(int argc, char* argv[]) { if (argc >= 2) g_sn = argv[1]; if (argc >= 3) g_sip = argv[2]; if (argc >= 4) g_port_req = atoi(argv[3]); if (argc >= 5) g_port_sub = atoi(argv[4]); std::cout << "Device SN: \t" << g_sn << std::endl; std::cout << "Server IP: \t" << g_sip << std::endl; std::cout << "Port_REQ: \t" << g_port_req << std::endl; std::cout << "Port_SUB: \t" << g_port_sub << std::endl; enet_initialize(); uv_loop_t *loop = uv_default_loop(); #ifndef RDC_LINUX_SYS std::string plugin_folder = GetModuleFilePath() + "\\plugins"; #else //std::string plugin_folder = GetModuleFilePath() + "/plugins"; std::string plugin_folder = "plugins"; #endif g_PluginLoader.Load(plugin_folder.c_str()); g_StreamMgr = new StreamMgr(loop); g_StreamMgr->Init(); void * ctx; ctx = zmq_ctx_new(); assert(ctx); int rc = create_req_socket(ctx); if (rc != 0) exit(EXIT_FAILURE); rc = Login(); if (rc != 0) { if (rc == -99) { printf("Device SN not authed!\n"); #ifndef RDC_LINUX_SYS Sleep(5000); #else sleep(5); #endif } exit(EXIT_FAILURE); } rc = create_sub_socket(ctx); if (rc != 0) exit(EXIT_FAILURE); uv_poll_t poll_sub; uv_os_sock_t socket; size_t len = sizeof(uv_os_sock_t); zmq_getsockopt(g_sub_socket, ZMQ_FD, &socket, &len); rc = uv_poll_init_socket(loop, &poll_sub, socket); assert(rc == 0); poll_sub.data = g_sub_socket; rc = uv_poll_start(&poll_sub, UV_READABLE, proccss_sub_msg); assert(rc == 0); uv_timer_t timer; rc = uv_timer_init(loop, &timer); assert(rc == 0); rc = uv_timer_start(&timer, Heartbeat_Timer, 1000, 20 * 1000); assert(rc == 0); //while (true) { // rc = uv_run(loop, UV_RUN_ONCE); //} uv_run(loop, UV_RUN_DEFAULT); rc = Logout(); uv_timer_stop(&timer); uv_poll_stop(&poll_sub); zmq_close(g_req_socket); zmq_close(g_sub_socket); zmq_ctx_term(ctx); g_StreamMgr->Close(); delete g_StreamMgr; g_PluginLoader.UnLoad(); enet_deinitialize(); #ifdef _DEBUG system("pause"); #endif return 0; }
void recv_msg(void* sock){ int retval = 0; zmq_msg_t msg; // Wow, fun bug. You have to set the identity before bind. No changing identity at runtime? #define IDENTITY "blaster.c" zmq_setsockopt(sock,ZMQ_IDENTITY,IDENTITY,strlen(IDENTITY)); retval = zmq_bind(sock,operation.destination); if(retval != 0){ switch(errno){ case EINVAL: puts("zmq_bind EINVAL"); break; case EPROTONOSUPPORT: puts("zmq_bind EPROTONOSUPPORT"); break; case ENOCOMPATPROTO: puts("zmq_bind ENOCOMPATPROTO"); break; case EADDRINUSE: puts("zmq_bind EADDRINUSE"); break; case EADDRNOTAVAIL: puts("zmq_bind EADDRNOTAVAIL"); break; case ENODEV: puts("zmq_bind ENODEV"); break; case ETERM: puts("zmq_bind ETERM"); break; case ENOTSOCK: puts("zmq_bind ENOTSOCK"); break; case EMTHREAD: puts("zmq_bind EMTHREAD"); break; default: puts("zmq_bind errno default"); } } char identity[256]; size_t identity_size; zmq_getsockopt(sock,ZMQ_IDENTITY,identity,&identity_size); printf("Server up (identity %.*s). Waiting for message.\n",(int)identity_size,identity); while(1){ zmq_msg_init(&msg); retval = zmq_recv(sock,&msg,0); if(retval != 0){ switch(errno){ case EAGAIN: puts("zmq_connect EAGAIN"); break; case ENOTSUP: puts("zmq_connect ENOTSUP"); break; case EFSM: puts("zmq_connect EFSM"); break; case ETERM: puts("zmq_connect ETERM"); break; case ENOTSOCK: puts("zmq_connect ENOTSOCK"); break; case EINTR: puts("zmq_connect EINTR"); break; case EFAULT: default: puts("zmq_recv errno default"); } } #ifdef LOGGING printf("Message %d '%.*s' (%d bytes)\n",message_count,(int)zmq_msg_size(&msg),zmq_msg_data(&msg),(int)zmq_msg_size(&msg)); message_count=message_count+1; #endif deliver_message(sock,10,0); zmq_msg_close(&msg); } }
int uwsgi_proto_zeromq_accept(struct wsgi_request *wsgi_req, int fd) { zmq_msg_t message; char *req_uuid = NULL; size_t req_uuid_len = 0; char *req_id = NULL; size_t req_id_len = 0; char *req_path = NULL; size_t req_path_len = 0; #ifdef UWSGI_JSON json_t *root; json_error_t error; #endif char *mongrel2_req = NULL; size_t mongrel2_req_size = 0; int resp_id_len; uint32_t events = 0; char *message_ptr; size_t message_size = 0; char *post_data; #ifdef ZMQ_EVENTS size_t events_len = sizeof(uint32_t); if (uwsgi.edge_triggered == 0) { if (zmq_getsockopt(pthread_getspecific(uwsgi.zmq_pull), ZMQ_EVENTS, &events, &events_len) < 0) { uwsgi_error("zmq_getsockopt()"); uwsgi.edge_triggered = 0; return -1; } } #endif if (events & ZMQ_POLLIN || uwsgi.edge_triggered) { wsgi_req->do_not_add_to_async_queue = 1; wsgi_req->proto_parser_status = 0; zmq_msg_init(&message); if (zmq_recv(pthread_getspecific(uwsgi.zmq_pull), &message, uwsgi.zeromq_recv_flag) < 0) { if (errno == EAGAIN) { uwsgi.edge_triggered = 0; } else { uwsgi_error("zmq_recv()"); } zmq_msg_close(&message); return -1; } uwsgi.edge_triggered = 1; message_size = zmq_msg_size(&message); //uwsgi_log("%.*s\n", (int) wsgi_req->proto_parser_pos, zmq_msg_data(&message)); if (message_size > 0xffff) { uwsgi_log("too much big message %d\n", message_size); zmq_msg_close(&message); wsgi_req->do_not_log = 1; return -1; } message_ptr = zmq_msg_data(&message); // warning mongrel2_req_size will contains a bad value, but this is not a problem... post_data = uwsgi_split4(message_ptr, message_size, ' ', &req_uuid, &req_uuid_len, &req_id, &req_id_len, &req_path, &req_path_len, &mongrel2_req, &mongrel2_req_size); if (post_data == NULL) { uwsgi_log("cannot parse message (split4 phase)\n"); zmq_msg_close(&message); wsgi_req->do_not_log = 1; return -1; } // fix post_data, mongrel2_req and mongrel2_req_size post_data = uwsgi_netstring(mongrel2_req, message_size - (mongrel2_req - message_ptr), &mongrel2_req, &mongrel2_req_size); if (post_data == NULL) { uwsgi_log("cannot parse message (body netstring phase)\n"); zmq_msg_close(&message); wsgi_req->do_not_log = 1; return -1; } // ok ready to parse tnetstring/json data and build uwsgi request if (mongrel2_req[mongrel2_req_size] == '}') { if (uwsgi_mongrel2_tnetstring_parse(wsgi_req, mongrel2_req, mongrel2_req_size)) { zmq_msg_close(&message); wsgi_req->do_not_log = 1; return -1; } } else { #ifdef UWSGI_JSON #ifdef UWSGI_DEBUG uwsgi_log("JSON %d: %.*s\n", mongrel2_req_size, mongrel2_req_size, mongrel2_req); #endif // add a zero to the end of buf mongrel2_req[mongrel2_req_size] = 0; root = json_loads(mongrel2_req, 0, &error); if (!root) { uwsgi_log("error parsing JSON data: line %d %s\n", error.line, error.text); zmq_msg_close(&message); wsgi_req->do_not_log = 1; return -1; } if (uwsgi_mongrel2_json_parse(root, wsgi_req)) { json_decref(root); zmq_msg_close(&message); wsgi_req->do_not_log = 1; return -1; } json_decref(root); #else uwsgi_log("JSON support not enabled (recompile uWSGI with libjansson support, or re-configure mongrel2 with \"protocol='tnetstring'\". skip request\n"); #endif } // pre-build the mongrel2 response_header wsgi_req->proto_parser_buf = uwsgi_malloc(req_uuid_len + 1 + 11 + 1 + req_id_len + 1 + 1); memcpy(wsgi_req->proto_parser_buf, req_uuid, req_uuid_len); ((char *) wsgi_req->proto_parser_buf)[req_uuid_len] = ' '; resp_id_len = uwsgi_num2str2(req_id_len, wsgi_req->proto_parser_buf + req_uuid_len + 1); ((char *) wsgi_req->proto_parser_buf)[req_uuid_len + 1 + resp_id_len] = ':'; memcpy((char *) wsgi_req->proto_parser_buf + req_uuid_len + 1 + resp_id_len + 1, req_id, req_id_len); memcpy((char *) wsgi_req->proto_parser_buf + req_uuid_len + 1 + resp_id_len + 1 + req_id_len, ", ", 2); wsgi_req->proto_parser_pos = (uint64_t) req_uuid_len + 1 + resp_id_len + 1 + req_id_len + 1 + 1; // handle post data if (wsgi_req->post_cl > 0 && !wsgi_req->async_post) { if (uwsgi_netstring(post_data, message_size - (post_data - message_ptr), &message_ptr, &wsgi_req->post_cl)) { #ifdef UWSGI_DEBUG uwsgi_log("post_size: %d\n", wsgi_req->post_cl); #endif wsgi_req->async_post = tmpfile(); if (fwrite(message_ptr, wsgi_req->post_cl, 1, wsgi_req->async_post) != 1) { uwsgi_error("fwrite()"); zmq_msg_close(&message); return -1; } rewind(wsgi_req->async_post); wsgi_req->body_as_file = 1; } } zmq_msg_close(&message); return 0; } return -1; }
static void test_stream_handshake_timeout_accept (void) { int rc; // Set up our context and sockets void *ctx = zmq_ctx_new (); assert (ctx); // We use this socket in raw mode, to make a connection and send nothing void *stream = zmq_socket (ctx, ZMQ_STREAM); assert (stream); int zero = 0; rc = zmq_setsockopt (stream, ZMQ_LINGER, &zero, sizeof (zero)); assert (rc == 0); rc = zmq_connect (stream, "tcp://localhost:5557"); assert (rc == 0); // We'll be using this socket to test TCP stream handshake timeout void *dealer = zmq_socket (ctx, ZMQ_DEALER); assert (dealer); rc = zmq_setsockopt (dealer, ZMQ_LINGER, &zero, sizeof (zero)); assert (rc == 0); int val, tenth = 100; size_t vsize = sizeof(val); // check for the expected default handshake timeout value - 30 sec rc = zmq_getsockopt (dealer, ZMQ_HANDSHAKE_IVL, &val, &vsize); assert (rc == 0); assert (vsize == sizeof(val)); assert (val == 30000); // make handshake timeout faster - 1/10 sec rc = zmq_setsockopt (dealer, ZMQ_HANDSHAKE_IVL, &tenth, sizeof (tenth)); assert (rc == 0); vsize = sizeof(val); // make sure zmq_setsockopt changed the value rc = zmq_getsockopt (dealer, ZMQ_HANDSHAKE_IVL, &val, &vsize); assert (rc == 0); assert (vsize == sizeof(val)); assert (val == tenth); // Create and connect a socket for collecting monitor events on dealer void *dealer_mon = zmq_socket (ctx, ZMQ_PAIR); assert (dealer_mon); rc = zmq_socket_monitor (dealer, "inproc://monitor-dealer", ZMQ_EVENT_CONNECTED | ZMQ_EVENT_DISCONNECTED | ZMQ_EVENT_ACCEPTED); assert (rc == 0); // Connect to the inproc endpoint so we'll get events rc = zmq_connect (dealer_mon, "inproc://monitor-dealer"); assert (rc == 0); // bind dealer socket to accept connection from non-sending stream socket rc = zmq_bind (dealer, "tcp://127.0.0.1:5557"); assert (rc == 0); // we should get ZMQ_EVENT_ACCEPTED and then ZMQ_EVENT_DISCONNECTED int event = get_monitor_event (dealer_mon, NULL, NULL); assert (event == ZMQ_EVENT_ACCEPTED); event = get_monitor_event (dealer_mon, NULL, NULL); assert (event == ZMQ_EVENT_DISCONNECTED); rc = zmq_close (dealer); assert (rc == 0); rc = zmq_close (dealer_mon); assert (rc == 0); rc = zmq_close (stream); assert (rc == 0); rc = zmq_ctx_term (ctx); assert (rc == 0); }
int main (void) { setup_test_environment (); size_t len = MAX_SOCKET_STRING; char my_endpoint[MAX_SOCKET_STRING]; void *ctx = zmq_ctx_new (); assert (ctx); void *req = zmq_socket (ctx, ZMQ_REQ); assert (req); void *router = zmq_socket (ctx, ZMQ_ROUTER); assert (router); int enabled = 1; int rc = zmq_setsockopt (req, ZMQ_REQ_CORRELATE, &enabled, sizeof (int)); assert (rc == 0); int rcvtimeo = 100; rc = zmq_setsockopt (req, ZMQ_RCVTIMEO, &rcvtimeo, sizeof (int)); assert (rc == 0); rc = zmq_bind (router, "tcp://127.0.0.1:*"); assert (rc == 0); rc = zmq_getsockopt (router, ZMQ_LAST_ENDPOINT, my_endpoint, &len); assert (rc == 0); rc = zmq_connect (req, my_endpoint); assert (rc == 0); // Send a multi-part request. s_send_seq (req, "ABC", "DEF", SEQ_END); zmq_msg_t msg; zmq_msg_init (&msg); // Receive peer routing id rc = zmq_msg_recv (&msg, router, 0); assert (rc != -1); assert (zmq_msg_size (&msg) > 0); zmq_msg_t peer_id_msg; zmq_msg_init (&peer_id_msg); zmq_msg_copy (&peer_id_msg, &msg); int more = 0; size_t more_size = sizeof (more); rc = zmq_getsockopt (router, ZMQ_RCVMORE, &more, &more_size); assert (rc == 0); assert (more); // Receive request id 1 rc = zmq_msg_recv (&msg, router, 0); assert (rc != -1); assert (zmq_msg_size (&msg) == sizeof (uint32_t)); uint32_t req_id = *static_cast<uint32_t *> (zmq_msg_data (&msg)); zmq_msg_t req_id_msg; zmq_msg_init (&req_id_msg); zmq_msg_copy (&req_id_msg, &msg); more = 0; more_size = sizeof (more); rc = zmq_getsockopt (router, ZMQ_RCVMORE, &more, &more_size); assert (rc == 0); assert (more); // Receive the rest. s_recv_seq (router, 0, "ABC", "DEF", SEQ_END); uint32_t bad_req_id = req_id + 1; // Send back a bad reply: wrong req id, 0, data zmq_msg_copy (&msg, &peer_id_msg); rc = zmq_msg_send (&msg, router, ZMQ_SNDMORE); assert (rc != -1); zmq_msg_init_data (&msg, &bad_req_id, sizeof (uint32_t), NULL, NULL); rc = zmq_msg_send (&msg, router, ZMQ_SNDMORE); assert (rc != -1); s_send_seq (router, 0, "DATA", SEQ_END); // Send back a good reply: good req id, 0, data zmq_msg_copy (&msg, &peer_id_msg); rc = zmq_msg_send (&msg, router, ZMQ_SNDMORE); assert (rc != -1); zmq_msg_copy (&msg, &req_id_msg); rc = zmq_msg_send (&msg, router, ZMQ_SNDMORE); assert (rc != -1); s_send_seq (router, 0, "GHI", SEQ_END); // Receive reply. If bad reply got through, we wouldn't see // this particular data. s_recv_seq (req, "GHI", SEQ_END); rc = zmq_msg_close (&msg); assert (rc == 0); rc = zmq_msg_close (&peer_id_msg); assert (rc == 0); rc = zmq_msg_close (&req_id_msg); assert (rc == 0); close_zero_linger (req); close_zero_linger (router); rc = zmq_ctx_term (ctx); assert (rc == 0); return 0; }
static int Lzmq_getsockopt(lua_State *L) { zmq_ptr *s = luaL_checkudata(L, 1, MT_ZMQ_SOCKET); int option = luaL_checkint(L, 2); size_t optvallen; int rc = 0; switch (option) { #if VERSION_2_1 case ZMQ_FD: { socket_t optval; optvallen = sizeof(socket_t); rc = zmq_getsockopt(s->ptr, option, (void *) &optval, &optvallen); if (rc == 0) { lua_pushinteger(L, (lua_Integer) optval); return 1; } } break; case ZMQ_EVENTS: { int32_t optval; optvallen = sizeof(int32_t); rc = zmq_getsockopt(s->ptr, option, (void *) &optval, &optvallen); if (rc == 0) { lua_pushinteger(L, (lua_Integer) optval); return 1; } } break; case ZMQ_TYPE: case ZMQ_LINGER: case ZMQ_RECONNECT_IVL: case ZMQ_BACKLOG: { int optval; optvallen = sizeof(int); rc = zmq_getsockopt(s->ptr, option, (void *) &optval, &optvallen); if (rc == 0) { lua_pushinteger(L, (lua_Integer) optval); return 1; } } break; #endif case ZMQ_SWAP: case ZMQ_RATE: case ZMQ_RECOVERY_IVL: case ZMQ_MCAST_LOOP: case ZMQ_RCVMORE: { int64_t optval; optvallen = sizeof(int64_t); rc = zmq_getsockopt(s->ptr, option, (void *) &optval, &optvallen); if (rc == 0) { lua_pushinteger(L, (lua_Integer) optval); return 1; } } break; case ZMQ_IDENTITY: { char id[256]; memset((void *)id, '\0', 256); optvallen = 256; rc = zmq_getsockopt(s->ptr, option, (void *)id, &optvallen); id[255] = '\0'; if (rc == 0) { lua_pushstring(L, id); return 1; } } break; case ZMQ_HWM: case ZMQ_AFFINITY: case ZMQ_SNDBUF: case ZMQ_RCVBUF: { uint64_t optval; optvallen = sizeof(uint64_t); rc = zmq_getsockopt(s->ptr, option, (void *) &optval, &optvallen); if (rc == 0) { lua_pushinteger(L, (lua_Integer) optval); return 1; } } break; default: rc = -1; errno = EINVAL; } if (rc != 0) { return Lzmq_push_error(L); } lua_pushboolean(L, 1); return 1; }
bool get_identity (void* socket, char* data, size_t* size) { int rc = zmq_getsockopt (socket, ZMQ_IDENTITY, data, size); return rc == 0; }
int zmq_poll (zmq_pollitem_t *items_, int nitems_, long timeout_) { #if defined ZMQ_POLL_BASED_ON_POLL if (unlikely (nitems_ < 0)) { errno = EINVAL; return -1; } if (unlikely (nitems_ == 0)) { if (timeout_ == 0) return 0; #if defined ZMQ_HAVE_WINDOWS Sleep (timeout_ > 0 ? timeout_ : INFINITE); return 0; #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 *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) { 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) { 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) { 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; } 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 } if (!items_) { errno = EFAULT; return -1; } 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)); int rc = select (maxfd + 1, &inset, &outset, &errset, ptimeout); #if defined ZMQ_HAVE_WINDOWS wsa_assert (rc != SOCKET_ERROR); #else if (rc == -1 && errno == EINTR) return -1; errno_assert (rc >= 0); #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 test_multi_connect (const char *address) { size_t len = MAX_SOCKET_STRING; char my_endpoint_0[MAX_SOCKET_STRING]; char my_endpoint_1[MAX_SOCKET_STRING]; char my_endpoint_2[MAX_SOCKET_STRING]; char my_endpoint_3[MAX_SOCKET_STRING * 2]; void *ctx = zmq_ctx_new (); assert (ctx); int ipv6; if (streq (address, "tcp://127.0.0.1:*")) ipv6 = 0; else if (streq (address, "tcp://[::1]:*")) ipv6 = 1; else assert (false); if (ipv6 && !is_ipv6_available ()) { zmq_ctx_term (ctx); return; } void *sb0 = zmq_socket (ctx, ZMQ_REP); assert (sb0); int rc = zmq_setsockopt (sb0, ZMQ_IPV6, &ipv6, sizeof (int)); assert (rc == 0); rc = zmq_bind (sb0, address); assert (rc == 0); rc = zmq_getsockopt (sb0, ZMQ_LAST_ENDPOINT, my_endpoint_0, &len); assert (rc == 0); void *sb1 = zmq_socket (ctx, ZMQ_REP); assert (sb1); rc = zmq_setsockopt (sb1, ZMQ_IPV6, &ipv6, sizeof (int)); assert (rc == 0); rc = zmq_bind (sb1, address); assert (rc == 0); len = MAX_SOCKET_STRING; rc = zmq_getsockopt (sb1, ZMQ_LAST_ENDPOINT, my_endpoint_1, &len); assert (rc == 0); void *sb2 = zmq_socket (ctx, ZMQ_REP); assert (sb2); rc = zmq_setsockopt (sb2, ZMQ_IPV6, &ipv6, sizeof (int)); assert (rc == 0); rc = zmq_bind (sb2, address); assert (rc == 0); len = MAX_SOCKET_STRING; rc = zmq_getsockopt (sb2, ZMQ_LAST_ENDPOINT, my_endpoint_2, &len); assert (rc == 0); void *sc = zmq_socket (ctx, ZMQ_REQ); assert (sc); rc = zmq_setsockopt (sc, ZMQ_IPV6, &ipv6, sizeof (int)); assert (rc == 0); rc = zmq_connect (sc, my_endpoint_0); assert (rc == 0); rc = zmq_connect (sc, my_endpoint_1); assert (rc == 0); if (!ipv6) sprintf (my_endpoint_3, "tcp://127.0.0.1:5564;%s", strrchr (my_endpoint_2, '/') + 1); else sprintf (my_endpoint_3, "tcp://[::1]:5564;%s", strrchr (my_endpoint_2, '/') + 1); rc = zmq_connect (sc, my_endpoint_3); assert (rc == 0); bounce (sb0, sc); bounce (sb1, sc); bounce (sb2, sc); bounce (sb0, sc); bounce (sb1, sc); bounce (sb2, sc); bounce (sb0, sc); rc = zmq_disconnect (sc, my_endpoint_0); assert (rc == 0); rc = zmq_disconnect (sc, my_endpoint_3); assert (rc == 0); rc = zmq_disconnect (sc, my_endpoint_1); assert (rc == 0); rc = zmq_unbind (sb0, my_endpoint_0); assert (rc == 0); rc = zmq_unbind (sb1, my_endpoint_1); assert (rc == 0); rc = zmq_unbind (sb2, my_endpoint_2); assert (rc == 0); rc = zmq_close (sc); assert (rc == 0); rc = zmq_close (sb0); assert (rc == 0); rc = zmq_close (sb1); assert (rc == 0); rc = zmq_close (sb2); assert (rc == 0); rc = zmq_ctx_term (ctx); assert (rc == 0); }
int main (int argc, char **argv) { int i, opt, thread = 1; char *command = NULL; char *frontendpoint = ZLMB_WORKER_SOCKET, *backendpoint = NULL; void *context, *frontend = NULL, *backend = NULL; zlmb_worker_t **worker = NULL; size_t size; const struct option long_options[] = { { "endpoint", 1, NULL, 'e' }, { "command", 1, NULL, 'c' }, { "thread", 1, NULL, 't' }, { "syslog", 0, NULL, 's' }, { "verbose", 0, NULL, 'v' }, { "help", 0, NULL, 'h' }, { NULL, 0, NULL, 0 } }; while ((opt = getopt_long(argc, argv, "e:c:t:svh", long_options, NULL)) != -1) { switch (opt) { case 'e': frontendpoint = optarg; break; case 'c': command = optarg; break; case 't': thread = atoi(optarg); break; case 's': _syslog = 1; break; case 'v': _verbose = 1; break; default: _usage(argv[0], NULL); return -1; } } _LOG_OPEN(ZLMB_SYSLOG_IDENT); _INFO("Connect endpoint: %s\n", frontendpoint); _INFO("Execute command: %s\n", command); _INFO("Thread count: %d\n", thread); context = zmq_ctx_new(); if (!context) { _ERR("ZeroMQ context: %s\n", zmq_strerror(errno)); _LOG_CLOSE(); return -1; } /* if (zmq_ctx_set(context, ZMQ_IO_THREADS, 1) == -1) { _ERR("%s", zmq_strerror(errno)); zmq_ctx_destroy(context); return -1; } if (zmq_ctx_set(context, ZMQ_MAX_SOCKETS, 1024) == -1) { _ERR("%s", zmq_strerror(errno)); zmq_ctx_destroy(context); return -1; } */ /* backend: command */ if (command) { backend = zmq_socket(context, ZMQ_PUSH); if (!backend) { _ERR("ZeroMQ backend socket: %s\n", zmq_strerror(errno)); zmq_ctx_destroy(context); _LOG_CLOSE(); return -1; } if (zlmb_utils_asprintf(&backendpoint, "%s.%d", ZLMB_WORKER_BACKEND_SOCKET, getpid()) == -1) { _ERR("Allocate string backend point.\n"); zmq_ctx_destroy(context); _LOG_CLOSE(); return -1; } if (zmq_bind(backend, backendpoint) == -1) { _ERR("ZeroMQ backend bind: %s: %s\n", backendpoint, zmq_strerror(errno)); zmq_close(backend); zmq_ctx_destroy(context); _LOG_CLOSE(); return -1; } _VERBOSE("ZeroMQ backend bind: %s\n", backendpoint); /* backend: command thread */ if (thread <= 0) { thread = 1; } size = sizeof(zlmb_worker_t *) * thread; worker = (zlmb_worker_t **)malloc(size); if (!worker) { _ERR("Memory allocate worker command.\n"); zmq_close(backend); zmq_ctx_destroy(context); free(backendpoint); _LOG_CLOSE(); return -1; } memset(worker, 0, size); for (i = 0; i != thread; i++) { worker[i] = (zlmb_worker_t *)malloc(sizeof(zlmb_worker_t)); if (!worker[i]) { _ERR("Memory allocate worker command.\n"); _worker_destroy(worker, thread, 500); zmq_close(backend); zmq_ctx_destroy(context); free(backendpoint); return -1; } worker[i]->thread = 0; worker[i]->context = context; worker[i]->command = command; worker[i]->endpoint = backendpoint; worker[i]->argv = argv; worker[i]->argc = argc; worker[i]->optind = optind; if (pthread_create(&(worker[i]->thread), NULL, _worker_command, (void *)worker[i]) == -1) { _ERR("Create command worker thread(#%d).\n", i+1); _worker_destroy(worker, thread, 500); zmq_close(backend); zmq_ctx_destroy(context); free(backendpoint); _LOG_CLOSE(); return -1; } } } /* frontend */ frontend = zmq_socket(context, ZMQ_PULL); if (!frontend) { _ERR("ZeroMQ frontend socket: %s\n", zmq_strerror(errno)); if (worker) { _worker_destroy(worker, thread, 500); zmq_close(backend); free(backendpoint); } zmq_ctx_destroy(context); _LOG_CLOSE(); return -1; } if (zmq_connect(frontend, frontendpoint) == -1) { _ERR("ZeroMQ frontend connect: %s: %s\n", frontendpoint, zmq_strerror(errno)); if (worker) { _worker_destroy(worker, thread, 500); zmq_close(backend); free(backendpoint); } zmq_close(frontend); zmq_ctx_destroy(context); _LOG_CLOSE(); return -1; } _VERBOSE("ZeroMQ frontend connect: %s\n", frontendpoint); _signals(); _VERBOSE("ZeroMQ start proxy.\n"); if (backend) { zmq_proxy(frontend, backend, NULL); } else { zmq_pollitem_t pollitems[] = { { frontend, 0, ZMQ_POLLIN, 0 } }; _NOTICE("default receive process.\n"); while (!_interrupted) { if (zmq_poll(pollitems, 1, -1) == -1) { break; } if (pollitems[0].revents & ZMQ_POLLIN) { int more; size_t moresz = sizeof(more); _DEBUG("ZeroMQ receive in poll event.\n"); while (!_interrupted) { zmq_msg_t zmsg; if (zmq_msg_init(&zmsg) != 0) { break; } _DEBUG("ZeroMQ receive message.\n"); if (zmq_recvmsg(frontend, &zmsg, 0) == -1) { _ERR("ZeroMQ frontend socket receive: %s\n", zmq_strerror(errno)); zmq_msg_close(&zmsg); break; } if (zmq_getsockopt(frontend, ZMQ_RCVMORE, &more, &moresz) == -1) { _ERR("ZeroMQ frontend socket option receive: %s\n", zmq_strerror(errno)); //zmq_msg_close(&zmsg); //break; more = 0; } #ifndef NDEBUG zlmb_dump_printmsg(stderr, &zmsg); #endif zmq_msg_close(&zmsg); if (!more) { break; } } } } } _VERBOSE("ZeroMQ end proxy.\n"); _VERBOSE("ZeroMQ close sockets.\n"); zmq_close(frontend); if (worker) { _worker_destroy(worker, thread, 0); zmq_close(backend); free(backendpoint); } _VERBOSE("ZeroMQ destory context.\n"); zmq_ctx_destroy(context); _LOG_CLOSE(); return 0; }
void test_req_only_listens_to_current_peer (void *ctx) { void *req = zmq_socket (ctx, ZMQ_REQ); assert (req); int rc = zmq_setsockopt(req, ZMQ_IDENTITY, "A", 2); assert (rc == 0); rc = zmq_bind (req, bind_address); assert (rc == 0); size_t len = MAX_SOCKET_STRING; rc = zmq_getsockopt (req, ZMQ_LAST_ENDPOINT, connect_address, &len); assert (rc == 0); const size_t services = 3; void *router [services]; for (size_t i = 0; i < services; ++i) { router [i] = zmq_socket (ctx, ZMQ_ROUTER); assert (router [i]); int timeout = 250; rc = zmq_setsockopt (router [i], ZMQ_RCVTIMEO, &timeout, sizeof (timeout)); assert (rc == 0); int enabled = 1; rc = zmq_setsockopt (router [i], ZMQ_ROUTER_MANDATORY, &enabled, sizeof (enabled)); assert (rc == 0); rc = zmq_connect (router [i], connect_address); assert (rc == 0); } // Wait for connects to finish. msleep (SETTLE_TIME); for (size_t i = 0; i < services; ++i) { // There still is a race condition when a stale peer's message // arrives at the REQ just after a request was sent to that peer. // To avoid that happening in the test, sleep for a bit. rc = zmq_poll (0, 0, 10); assert (rc == 0); s_send_seq (req, "ABC", SEQ_END); // Receive on router i s_recv_seq (router [i], "A", 0, "ABC", SEQ_END); // Send back replies on all routers for (size_t j = 0; j < services; ++j) { const char *replies [] = { "WRONG", "GOOD" }; const char *reply = replies [i == j ? 1 : 0]; s_send_seq (router [j], "A", 0, reply, SEQ_END); } // Receive only the good reply s_recv_seq (req, "GOOD", SEQ_END); } close_zero_linger (req); for (size_t i = 0; i < services; ++i) close_zero_linger (router [i]); // Wait for disconnects. msleep (SETTLE_TIME); }
static void * _worker_command(void *arg) { zlmb_worker_t *worker = (zlmb_worker_t *)arg; zmq_pollitem_t pollitems[] = { { NULL, 0, ZMQ_POLLIN, 0 } }; void *socket; if (!worker || !worker->context || !worker->command) { _ERR("Function arguments: %s\n", __FUNCTION__); return NULL; } socket = zmq_socket(worker->context, ZMQ_PULL); if (!socket) { _ERR("ZeroMQ socket: %s\n", zmq_strerror(errno)); return NULL; } if (zmq_connect(socket, worker->endpoint) == -1) { _ERR("ZeroMQ socket connect: %s: %s\n", worker->endpoint, zmq_strerror(errno)); zmq_close(socket); return NULL; } _VERBOSE("ZeroMQ socket connect: %s\n", worker->endpoint); _VERBOSE("ZeroMQ start worker command proxy.\n"); pollitems[0].socket = socket; _signals(); while (!_interrupted) { if (zmq_poll(pollitems, 1, -1) == -1) { break; } if (pollitems[0].revents & ZMQ_POLLIN) { int more; size_t moresz = sizeof(more); zlmb_spawn_t spawn = { NULL, NULL, NULL, NULL }; _DEBUG("ZeroMQ receive in poll event.\n"); spawn.stack = zlmb_stack_init(); if (!spawn.stack) { _ERR("Message stack initilize.\n"); break; } while (!_interrupted) { zmq_msg_t *zmsg = (zmq_msg_t *)malloc(sizeof(zmq_msg_t)); if (!zmsg) { break; } _DEBUG("ZeroMQ receive message.\n"); if (zmq_msg_init(zmsg) != 0) { break; } if (zmq_recvmsg(socket, zmsg, 0) == -1) { _ERR("ZeroMQ socket receive: %s\n", zmq_strerror(errno)); zmq_msg_close(zmsg); free(zmsg); break; } if (zmq_getsockopt(socket, ZMQ_RCVMORE, &more, &moresz) == -1) { _ERR("ZeroMQ socket option receive: %s\n", zmq_strerror(errno)); more = 0; } if (zlmb_stack_push(spawn.stack, zmsg) != 0) { _ERR("Message stack push.\n"); } if (!more) { break; } } //env _spawn_generate_environ(&spawn); //spawn _spawn_run(&spawn, worker->command, worker->argc, worker->argv, worker->optind); _spawn_destroy(&spawn); } } _VERBOSE("ZeroMQ end worker command proxy.\n"); zmq_close(socket); return NULL; }
Bool HawkZmqManager::ProxyZmq(HawkZmq* pFrontend, HawkZmq* pBackend, Bool bBothway, Int32 iTimeout, Bool bOnce) { HawkAssert(pFrontend && pBackend); if (!pFrontend || !pBackend) return false; zmq_pollitem_t items[] = { { pFrontend->GetHandle(), 0, 0, 0 }, { pBackend->GetHandle(), 0, 0, 0 } }; items[0].events = ZMQ_POLLIN; if (bBothway) items[1].events = ZMQ_POLLIN; do { items[0].revents = 0; items[1].revents = 0; if (zmq_poll(items, 2, iTimeout) < 0) return false; if (items[0].revents & ZMQ_POLLIN) { zmq_msg_t sMsg; if (zmq_msg_init(&sMsg) != HAWK_OK) return false; while (true) { if (zmq_recvmsg(items[0].socket, &sMsg, 0) < 0) { zmq_msg_close(&sMsg); return false; } Int32 iRecvMore = 0; Size_t iLen = sizeof(iRecvMore); if (zmq_getsockopt(items[0].socket, ZMQ_RCVMORE, &iRecvMore, &iLen) < 0) { zmq_msg_close(&sMsg); return false; } if (zmq_sendmsg(items[1].socket, &sMsg, iRecvMore? ZMQ_SNDMORE : 0) < 0) { zmq_msg_close(&sMsg); return false; } if (iRecvMore == 0) break; } //ÊÍ·ÅÏûÏ¢ zmq_msg_close(&sMsg); } if (items[1].revents & ZMQ_POLLIN) { zmq_msg_t sMsg; if (zmq_msg_init(&sMsg) != HAWK_OK) return false; while (true) { if (zmq_recvmsg(items[1].socket, &sMsg, 0) < 0) { zmq_msg_close(&sMsg); return false; } Int32 iRecvMore = 0; Size_t iLen = sizeof(iRecvMore); if (zmq_getsockopt(items[1].socket, ZMQ_RCVMORE, &iRecvMore, &iLen) < 0) { zmq_msg_close(&sMsg); return false; } if (zmq_sendmsg(items[0].socket, &sMsg, iRecvMore? ZMQ_SNDMORE: 0) < 0) { zmq_msg_close(&sMsg); return false; } if (iRecvMore == 0) break; } zmq_msg_close(&sMsg); } }while(!bOnce); return true; }
int main (void) { size_t len = MAX_SOCKET_STRING; char my_endpoint_0[MAX_SOCKET_STRING]; char my_endpoint_1[MAX_SOCKET_STRING]; setup_test_environment (); void *ctx = zmq_ctx_new (); assert (ctx); // Create few sockets void *vent = zmq_socket (ctx, ZMQ_PUSH); assert (vent); int rc = zmq_bind (vent, "tcp://127.0.0.1:*"); assert (rc == 0); rc = zmq_getsockopt (vent, ZMQ_LAST_ENDPOINT, my_endpoint_0, &len); assert (rc == 0); void *sink = zmq_socket (ctx, ZMQ_PULL); assert (sink); rc = zmq_connect (sink, my_endpoint_0); assert (rc == 0); void *bowl = zmq_socket (ctx, ZMQ_PULL); assert (bowl); #if defined(ZMQ_SERVER) && defined(ZMQ_CLIENT) void *server = zmq_socket (ctx, ZMQ_SERVER); assert (server); rc = zmq_bind (server, "tcp://127.0.0.1:*"); assert (rc == 0); len = MAX_SOCKET_STRING; rc = zmq_getsockopt (server, ZMQ_LAST_ENDPOINT, my_endpoint_1, &len); assert (rc == 0); void *client = zmq_socket (ctx, ZMQ_CLIENT); assert (client); #endif // Set up poller void* poller = zmq_poller_new (); zmq_poller_event_t event; // waiting on poller with no registered sockets should report error rc = zmq_poller_wait(poller, &event, 0); assert (rc == -1); assert (errno == ETIMEDOUT); // register sink rc = zmq_poller_add (poller, sink, sink, ZMQ_POLLIN); assert (rc == 0); // Send a message char data[1] = {'H'}; rc = zmq_send_const (vent, data, 1, 0); assert (rc == 1); // We expect a message only on the sink rc = zmq_poller_wait (poller, &event, -1); assert (rc == 0); assert (event.socket == sink); assert (event.user_data == sink); rc = zmq_recv (sink, data, 1, 0); assert (rc == 1); // We expect timed out rc = zmq_poller_wait (poller, &event, 0); assert (rc == -1); assert (errno == ETIMEDOUT); // Stop polling sink rc = zmq_poller_remove (poller, sink); assert (rc == 0); // Check we can poll an FD rc = zmq_connect (bowl, my_endpoint_0); assert (rc == 0); #if defined _WIN32 SOCKET fd; size_t fd_size = sizeof (SOCKET); #else int fd; size_t fd_size = sizeof (int); #endif rc = zmq_getsockopt (bowl, ZMQ_FD, &fd, &fd_size); assert (rc == 0); rc = zmq_poller_add_fd (poller, fd, bowl, ZMQ_POLLIN); assert (rc == 0); rc = zmq_poller_wait (poller, &event, 500); assert (rc == 0); assert (event.socket == NULL); assert (event.fd == fd); assert (event.user_data == bowl); zmq_poller_remove_fd (poller, fd); #if defined(ZMQ_SERVER) && defined(ZMQ_CLIENT) // Polling on thread safe sockets rc = zmq_poller_add (poller, server, NULL, ZMQ_POLLIN); assert (rc == 0); rc = zmq_connect (client, my_endpoint_1); assert (rc == 0); rc = zmq_send_const (client, data, 1, 0); assert (rc == 1); rc = zmq_poller_wait (poller, &event, 500); assert (rc == 0); assert (event.socket == server); assert (event.user_data == NULL); rc = zmq_recv (server, data, 1, 0); assert (rc == 1); // Polling on pollout rc = zmq_poller_modify (poller, server, ZMQ_POLLOUT | ZMQ_POLLIN); assert (rc == 0); rc = zmq_poller_wait (poller, &event, 0); assert (rc == 0); assert (event.socket == server); assert (event.user_data == NULL); assert (event.events == ZMQ_POLLOUT); // Stop polling server rc = zmq_poller_remove (poller, server); assert (rc == 0); #endif // Destory sockets, poller and ctx rc = zmq_close (sink); assert (rc == 0); rc = zmq_close (vent); assert (rc == 0); rc = zmq_close (bowl); assert (rc == 0); #if defined(ZMQ_SERVER) && defined(ZMQ_CLIENT) rc = zmq_close (server); assert (rc == 0); rc = zmq_close (client); assert (rc == 0); #endif // Test error - null poller pointers rc = zmq_poller_destroy (NULL); assert (rc == -1 && errno == EFAULT); void *null_poller = NULL; rc = zmq_poller_destroy (&null_poller); assert (rc == -1 && errno == EFAULT); rc = zmq_poller_destroy (&poller); assert(rc == 0); rc = zmq_ctx_term (ctx); assert (rc == 0); return 0; }
static void zmqdrv_getsockopt(zmq_drv_t *drv, ErlIOVec *ev) { ErlDrvBinary* bin = ev->binv[1]; char* bytes = bin->orig_bytes; uint32_t idx = ntohl(*(uint32_t*)(bytes+1)); void* s = drv->get_zmq_socket(idx); zmq_sock_info* si = drv->get_socket_info(idx); uint32_t opt = ntohl (*(uint32_t*)(bytes+sizeof(idx)+1)); union { uint8_t a[255]; uint64_t ui64; int64_t i64; int i; uint32_t ui; } val; size_t vallen; if (idx > drv->zmq_socket_count || !s || !si) { zmqdrv_error_code(drv, ENODEV); return; } zmqdrv_fprintf("setsockopt %p (setting %d options)\r\n", si->socket, (int)n); switch (opt) { case ZMQ_AFFINITY: vallen = sizeof(uint64_t); if (zmq_getsockopt(s, opt, &val.ui64, &vallen) < 0) zmqdrv_error_code(drv, zmq_errno()); zmqdrv_ok_int64(drv, driver_caller(drv->port), val.ui64); break; case ZMQ_BACKLOG: vallen = sizeof(int); if (zmq_getsockopt(s, opt, &val.i, &vallen) < 0) zmqdrv_error_code(drv, zmq_errno()); zmqdrv_ok_int64(drv, driver_caller(drv->port), val.i); break; case ZMQ_EVENTS: vallen = sizeof(uint32_t); if (zmq_getsockopt(s, opt, &val.ui, &vallen) < 0) zmqdrv_error_code(drv, zmq_errno()); zmqdrv_ok_int64(drv, driver_caller(drv->port), val.ui); break; case ZMQ_FD: vallen = sizeof(int); if (zmq_getsockopt(s, opt, &val.i, &vallen) < 0) zmqdrv_error_code(drv, zmq_errno()); zmqdrv_ok_int64(drv, driver_caller(drv->port), val.i); break; case ZMQ_HWM: vallen = sizeof(uint64_t); if (zmq_getsockopt(s, opt, &val.ui64, &vallen) < 0) zmqdrv_error_code(drv, zmq_errno()); zmqdrv_ok_int64(drv, driver_caller(drv->port), val.ui64); break; case ZMQ_IDENTITY: vallen = sizeof(val); if (zmq_getsockopt(s, opt, val.a, &vallen) < 0) zmqdrv_error_code(drv, zmq_errno()); zmqdrv_ok_binary(drv, driver_caller(drv->port), val.a, vallen); break; case ZMQ_LINGER: vallen = sizeof(int); if (zmq_getsockopt(s, opt, &val.i, &vallen) < 0) zmqdrv_error_code(drv, zmq_errno()); zmqdrv_ok_bool(drv, driver_caller(drv->port), !!val.i); break; case ZMQ_MCAST_LOOP: vallen = sizeof(int64_t); if (zmq_getsockopt(s, opt, &val.i64, &vallen) < 0) zmqdrv_error_code(drv, zmq_errno()); zmqdrv_ok_bool(drv, driver_caller(drv->port), !!val.i64); break; case ZMQ_RATE: vallen = sizeof(int64_t); if (zmq_getsockopt(s, opt, &val.i64, &vallen) < 0) zmqdrv_error_code(drv, zmq_errno()); zmqdrv_ok_int64(drv, driver_caller(drv->port), val.i64); break; case ZMQ_RCVBUF: vallen = sizeof(uint64_t); if (zmq_getsockopt(s, opt, &val.ui64, &vallen) < 0) zmqdrv_error_code(drv, zmq_errno()); zmqdrv_ok_int64(drv, driver_caller(drv->port), val.ui64); break; case ZMQ_RCVMORE: vallen = sizeof(int64_t); if (zmq_getsockopt(s, opt, &val.i64, &vallen) < 0) zmqdrv_error_code(drv, zmq_errno()); zmqdrv_ok_bool(drv, driver_caller(drv->port), !!val.i64); break; case ZMQ_RECONNECT_IVL: vallen = sizeof(int); if (zmq_getsockopt(s, opt, &val.i, &vallen) < 0) zmqdrv_error_code(drv, zmq_errno()); zmqdrv_ok_int64(drv, driver_caller(drv->port), val.i); break; case ZMQ_RECOVERY_IVL: vallen = sizeof(int64_t); if (zmq_getsockopt(s, opt, &val.i64, &vallen) < 0) zmqdrv_error_code(drv, zmq_errno()); zmqdrv_ok_int64(drv, driver_caller(drv->port), val.i64); break; case ZMQ_RECOVERY_IVL_MSEC: vallen = sizeof(int64_t); if (zmq_getsockopt(s, opt, &val.i64, &vallen) < 0) zmqdrv_error_code(drv, zmq_errno()); zmqdrv_ok_int64(drv, driver_caller(drv->port), val.i64); break; case ZMQ_SNDBUF: vallen = sizeof(uint64_t); if (zmq_getsockopt(s, opt, &val.ui64, &vallen) < 0) zmqdrv_error_code(drv, zmq_errno()); zmqdrv_ok_int64(drv, driver_caller(drv->port), val.ui64); break; case ZMQ_SWAP: vallen = sizeof(int64_t); if (zmq_getsockopt(s, opt, &val.i64, &vallen) < 0) zmqdrv_error_code(drv, zmq_errno()); zmqdrv_ok_int64(drv, driver_caller(drv->port), val.i64); break; case ZMQ_TYPE: vallen = sizeof(int); if (zmq_getsockopt(s, opt, &val.i, &vallen) < 0) zmqdrv_error_code(drv, zmq_errno()); zmqdrv_ok_int64(drv, driver_caller(drv->port), val.i); break; case ZMQ_ACTIVE: zmqdrv_ok_bool(drv, driver_caller(drv->port), si->active_mode); break; default: zmqdrv_error(drv, "Option not implemented!"); return; } }
static void zmqdrv_ready_input(ErlDrvData handle, ErlDrvEvent event) { zmq_drv_t *drv = (zmq_drv_t *)handle; // Get 0MQ sockets managed by application thread's signaler // identified by "event" fd. zmq_fd_sockets_map_t::iterator it = drv->zmq_fd_sockets.find((long)event); zmqdrv_fprintf("input ready on [idx=%ld]\r\n", (long)event); assert(it != drv->zmq_fd_sockets.end()); zmq_sock_set_t::iterator si = it->second.begin(); assert(si != it->second.end()); for (; si != it->second.end(); ++si) { zmq_socket_t s = (*si)->socket; uint32_t idx = (*si)->idx; ErlDrvTermData owner = (*si)->owner; int rc = 0; uint32_t events; size_t events_size = sizeof(events); zmq_getsockopt(s, ZMQ_EVENTS, &events, &events_size); while (((*si)->active_mode || (*si)->in_caller) && (events & ZMQ_POLLIN)) { msg_t msg; rc = zmq_recv(s, &msg, ZMQ_NOBLOCK); ErlDrvTermData pid = (*si)->active_mode ? owner : (*si)->in_caller; if (rc == -1) { if (zmq_errno() != EAGAIN) { ErlDrvTermData spec[] = {ERL_DRV_ATOM, am_zmq, ERL_DRV_UINT, idx, ERL_DRV_ATOM, error_atom(zmq_errno()), ERL_DRV_TUPLE, 2, ERL_DRV_TUPLE, 3}; driver_send_term(drv->port, owner, spec, sizeof(spec)/sizeof(spec[0])); (*si)->in_caller = 0; } break; } if ((*si)->active_mode) { // Send message {zmq, Socket, binary()} to the owner pid ErlDrvTermData spec[] = {ERL_DRV_ATOM, am_zmq, ERL_DRV_UINT, idx, ERL_DRV_BUF2BINARY, (ErlDrvTermData)zmq_msg_data(&msg), zmq_msg_size(&msg), ERL_DRV_TUPLE, 3}; driver_send_term(drv->port, owner, spec, sizeof(spec)/sizeof(spec[0])); } else { // Return result {ok, binary()} to the waiting caller's pid ErlDrvTermData spec[] = {ERL_DRV_ATOM, am_zok, ERL_DRV_BUF2BINARY, (ErlDrvTermData)zmq_msg_data(&msg), zmq_msg_size(&msg), ERL_DRV_TUPLE, 2}; driver_send_term(drv->port, pid, spec, sizeof(spec)/sizeof(spec[0])); (*si)->in_caller = 0; } // FIXME: add error handling zmqdrv_fprintf("received %ld byte message relayed to pid %ld\r\n", zmq_msg_size(&msg), pid); zmq_getsockopt(s, ZMQ_EVENTS, &events, &events_size); } zmq_getsockopt(s, ZMQ_EVENTS, &events, &events_size); if ((*si)->out_caller != 0 && (events & ZMQ_POLLOUT)) { // There was a pending unwritten message on this socket. // Try to write it. If the write succeeds/fails clear the ZMQ_POLLOUT // flag and notify the waiting caller of completion of operation. rc = zmq_send(s, &(*si)->out_msg, (*si)->out_flags | ZMQ_NOBLOCK); zmqdrv_fprintf("resending message %p (size=%ld) on socket %p (ret=%d)\r\n", zmq_msg_data(&(*si)->out_msg), zmq_msg_size(&(*si)->out_msg), s, rc); if (rc == 0) { zmq_msg_close(&(*si)->out_msg); // Unblock the waiting caller's pid by returning result zmqdrv_ok(drv, (*si)->out_caller); (*si)->out_caller = 0; } else if (zmq_errno() != EAGAIN) { // Unblock the waiting caller's pid by returning result zmq_msg_close(&(*si)->out_msg); zmqdrv_socket_error(drv, (*si)->out_caller, idx, zmq_errno()); (*si)->out_caller = 0; } } zmqdrv_fprintf("--> socket %p events=%d\r\n", s, events); } }