void test_bind_before_connect () { // Bind first void *bind_socket = test_context_socket (ZMQ_PAIR); TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (bind_socket, "inproc://bbc")); // Now connect void *connect_socket = test_context_socket (ZMQ_PAIR); TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (connect_socket, "inproc://bbc")); // Queue up some data send_string_expect_success (connect_socket, "foobar", 0); // Read pending message recv_string_expect_success (bind_socket, "foobar", 0); // Cleanup test_context_socket_close (connect_socket); test_context_socket_close (bind_socket); }
static void test_stream_to_dealer () { int rc; char my_endpoint[MAX_SOCKET_STRING]; // We'll be using this socket in raw mode void *stream = test_context_socket (ZMQ_STREAM); int zero = 0; TEST_ASSERT_SUCCESS_ERRNO ( zmq_setsockopt (stream, ZMQ_LINGER, &zero, sizeof (zero))); int enabled = 1; TEST_ASSERT_SUCCESS_ERRNO ( zmq_setsockopt (stream, ZMQ_STREAM_NOTIFY, &enabled, sizeof (enabled))); bind_loopback_ipv4 (stream, my_endpoint, sizeof my_endpoint); // We'll be using this socket as the other peer void *dealer = test_context_socket (ZMQ_DEALER); TEST_ASSERT_SUCCESS_ERRNO ( zmq_setsockopt (dealer, ZMQ_LINGER, &zero, sizeof (zero))); TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (dealer, my_endpoint)); // Send a message on the dealer socket send_string_expect_success (dealer, "Hello", 0); // Connecting sends a zero message // First frame is routing id zmq_msg_t routing_id; TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_init (&routing_id)); TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_recv (&routing_id, stream, 0)); TEST_ASSERT_TRUE (zmq_msg_more (&routing_id)); // Verify the existence of Peer-Address metadata char const *peer_address = zmq_msg_gets (&routing_id, "Peer-Address"); TEST_ASSERT_NOT_NULL (peer_address); TEST_ASSERT_EQUAL_STRING ("127.0.0.1", peer_address); // Second frame is zero byte buffer[255]; TEST_ASSERT_EQUAL_INT ( 0, TEST_ASSERT_SUCCESS_ERRNO (zmq_recv (stream, buffer, 255, 0))); // Verify the existence of Peer-Address metadata peer_address = zmq_msg_gets (&routing_id, "Peer-Address"); TEST_ASSERT_NOT_NULL (peer_address); TEST_ASSERT_EQUAL_STRING ("127.0.0.1", peer_address); // Real data follows // First frame is routing id TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_recv (&routing_id, stream, 0)); TEST_ASSERT_TRUE (zmq_msg_more (&routing_id)); // Verify the existence of Peer-Address metadata peer_address = zmq_msg_gets (&routing_id, "Peer-Address"); TEST_ASSERT_NOT_NULL (peer_address); TEST_ASSERT_EQUAL_STRING ("127.0.0.1", peer_address); // Second frame is greeting signature recv_array_expect_success (stream, greeting.signature, 0); // Send our own protocol greeting TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_send (&routing_id, stream, ZMQ_SNDMORE)); TEST_ASSERT_EQUAL_INT ( sizeof (greeting), TEST_ASSERT_SUCCESS_ERRNO ( zmq_send (stream, &greeting, sizeof (greeting), 0))); // Now we expect the data from the DEALER socket // We want the rest of greeting along with the Ready command int bytes_read = 0; while (bytes_read < 97) { // First frame is the routing id of the connection (each time) TEST_ASSERT_GREATER_THAN_INT ( 0, TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_recv (&routing_id, stream, 0))); TEST_ASSERT_TRUE (zmq_msg_more (&routing_id)); // Second frame contains the next chunk of data TEST_ASSERT_SUCCESS_ERRNO ( rc = zmq_recv (stream, buffer + bytes_read, 255 - bytes_read, 0)); bytes_read += rc; } // First two bytes are major and minor version numbers. TEST_ASSERT_EQUAL_INT (3, buffer[0]); // ZMTP/3.0 TEST_ASSERT_EQUAL_INT (0, buffer[1]); // Mechanism is "NULL" TEST_ASSERT_EQUAL_INT8_ARRAY (buffer + 2, "NULL\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20); TEST_ASSERT_EQUAL_INT8_ARRAY (buffer + 54, "\4\51\5READY", 8); TEST_ASSERT_EQUAL_INT8_ARRAY (buffer + 62, "\13Socket-Type\0\0\0\6DEALER", 22); TEST_ASSERT_EQUAL_INT8_ARRAY (buffer + 84, "\10Identity\0\0\0\0", 13); // Announce we are ready memcpy (buffer, "\4\51\5READY", 8); memcpy (buffer + 8, "\13Socket-Type\0\0\0\6ROUTER", 22); memcpy (buffer + 30, "\10Identity\0\0\0\0", 13); // Send Ready command TEST_ASSERT_GREATER_THAN_INT (0, TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_send ( &routing_id, stream, ZMQ_SNDMORE))); TEST_ASSERT_EQUAL_INT ( 43, TEST_ASSERT_SUCCESS_ERRNO (zmq_send (stream, buffer, 43, 0))); // Now we expect the data from the DEALER socket // First frame is, again, the routing id of the connection TEST_ASSERT_GREATER_THAN_INT ( 0, TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_recv (&routing_id, stream, 0))); TEST_ASSERT_TRUE (zmq_msg_more (&routing_id)); // Third frame contains Hello message from DEALER TEST_ASSERT_EQUAL_INT (7, TEST_ASSERT_SUCCESS_ERRNO ( zmq_recv (stream, buffer, sizeof buffer, 0))); // Then we have a 5-byte message "Hello" TEST_ASSERT_EQUAL_INT (0, buffer[0]); // Flags = 0 TEST_ASSERT_EQUAL_INT (5, buffer[1]); // Size = 5 TEST_ASSERT_EQUAL_INT8_ARRAY (buffer + 2, "Hello", 5); // Send "World" back to DEALER TEST_ASSERT_GREATER_THAN_INT (0, TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_send ( &routing_id, stream, ZMQ_SNDMORE))); byte world[] = {0, 5, 'W', 'o', 'r', 'l', 'd'}; TEST_ASSERT_EQUAL_INT ( sizeof (world), TEST_ASSERT_SUCCESS_ERRNO (zmq_send (stream, world, sizeof (world), 0))); // Expect response on DEALER socket recv_string_expect_success (dealer, "World", 0); // Test large messages over STREAM socket #define size 64000 uint8_t msgout[size]; memset (msgout, 0xAB, size); zmq_send (dealer, msgout, size, 0); uint8_t msgin[9 + size]; memset (msgin, 0, 9 + size); bytes_read = 0; while (bytes_read < 9 + size) { // Get routing id frame TEST_ASSERT_GREATER_THAN_INT ( 0, TEST_ASSERT_SUCCESS_ERRNO (zmq_recv (stream, buffer, 256, 0))); // Get next chunk TEST_ASSERT_GREATER_THAN_INT ( 0, TEST_ASSERT_SUCCESS_ERRNO (rc = zmq_recv (stream, msgin + bytes_read, 9 + size - bytes_read, 0))); bytes_read += rc; } for (int byte_nbr = 0; byte_nbr < size; byte_nbr++) { TEST_ASSERT_EQUAL_UINT8 (0xAB, msgin[9 + byte_nbr]); } test_context_socket_close (dealer); test_context_socket_close (stream); }
void test_get_peer_state () { #ifdef ZMQ_BUILD_DRAFT_API void *router = test_context_socket (ZMQ_ROUTER); int mandatory = 1; TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (router, ZMQ_ROUTER_MANDATORY, &mandatory, sizeof (mandatory))); const char *my_endpoint = "inproc://test_get_peer_state"; TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (router, my_endpoint)); void *dealer1 = test_context_socket (ZMQ_DEALER); void *dealer2 = test_context_socket (ZMQ_DEALER); // Lower HWMs to allow doing the test with fewer messages const int hwm = 100; TEST_ASSERT_SUCCESS_ERRNO ( zmq_setsockopt (router, ZMQ_SNDHWM, &hwm, sizeof (int))); TEST_ASSERT_SUCCESS_ERRNO ( zmq_setsockopt (dealer1, ZMQ_RCVHWM, &hwm, sizeof (int))); TEST_ASSERT_SUCCESS_ERRNO ( zmq_setsockopt (dealer2, ZMQ_RCVHWM, &hwm, sizeof (int))); const char *dealer1_routing_id = "X"; const char *dealer2_routing_id = "Y"; // Name dealer1 "X" and connect it to our router TEST_ASSERT_SUCCESS_ERRNO ( zmq_setsockopt (dealer1, ZMQ_ROUTING_ID, dealer1_routing_id, 1)); TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (dealer1, my_endpoint)); // Name dealer2 "Y" and connect it to our router TEST_ASSERT_SUCCESS_ERRNO ( zmq_setsockopt (dealer2, ZMQ_ROUTING_ID, dealer2_routing_id, 1)); TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (dealer2, my_endpoint)); // Get message from both dealers to know when connection is ready send_string_expect_success (dealer1, "Hello", 0); recv_string_expect_success (router, dealer1_routing_id, 0); recv_string_expect_success (router, "Hello", 0); send_string_expect_success (dealer2, "Hello", 0); recv_string_expect_success (router, dealer2_routing_id, 0); recv_string_expect_success (router, "Hello", 0); void *poller = zmq_poller_new (); TEST_ASSERT_NOT_NULL (poller); // Poll on router and dealer1, but not on dealer2 TEST_ASSERT_SUCCESS_ERRNO ( zmq_poller_add (poller, router, NULL, ZMQ_POLLOUT)); TEST_ASSERT_SUCCESS_ERRNO ( zmq_poller_add (poller, dealer1, NULL, ZMQ_POLLIN)); const unsigned int count = 10000; const unsigned int event_size = 2; bool dealer2_blocked = false; unsigned int dealer1_sent = 0, dealer2_sent = 0, dealer1_received = 0; zmq_poller_event_t events[event_size]; for (unsigned int iteration = 0; iteration < count; ++iteration) { TEST_ASSERT_SUCCESS_ERRNO ( zmq_poller_wait_all (poller, events, event_size, -1)); for (unsigned int event_no = 0; event_no < event_size; ++event_no) { const zmq_poller_event_t ¤t_event = events[event_no]; if (current_event.socket == router && current_event.events & ZMQ_POLLOUT) { if (send_msg_to_peer_if_ready (router, dealer1_routing_id)) ++dealer1_sent; if (send_msg_to_peer_if_ready (router, dealer2_routing_id)) ++dealer2_sent; else dealer2_blocked = true; } if (current_event.socket == dealer1 && current_event.events & ZMQ_POLLIN) { recv_string_expect_success (dealer1, "Hello", ZMQ_DONTWAIT); int more; size_t more_size = sizeof (more); TEST_ASSERT_SUCCESS_ERRNO ( zmq_getsockopt (dealer1, ZMQ_RCVMORE, &more, &more_size)); TEST_ASSERT_FALSE (more); ++dealer1_received; } // never read from dealer2, so its pipe becomes full eventually } } printf ("dealer1_sent = %u, dealer2_sent = %u, dealer1_received = %u\n", dealer1_sent, dealer2_sent, dealer1_received); TEST_ASSERT_TRUE (dealer2_blocked); zmq_poller_destroy (&poller); test_context_socket_close (router); test_context_socket_close (dealer1); test_context_socket_close (dealer2); #endif }
void test_send_one_connected_one_unconnected_with_delay () { int val; // TEST 2 // This time we will do the same thing, connect two pipes, // one of which will succeed in connecting to a bound // receiver, the other of which will fail. However, we will // also set the delay attach on connect flag, which should // cause the pipe attachment to be delayed until the connection // succeeds. // Bind the valid socket void *to = test_context_socket (ZMQ_PULL); TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (to, "tipc://{5560,0,0}")); val = 0; TEST_ASSERT_SUCCESS_ERRNO ( zmq_setsockopt (to, ZMQ_LINGER, &val, sizeof (val))); // Create a socket pushing to two endpoints - all messages should arrive. void *from = test_context_socket (ZMQ_PUSH); val = 0; TEST_ASSERT_SUCCESS_ERRNO ( zmq_setsockopt (from, ZMQ_LINGER, &val, sizeof (val))); // Set the key flag val = 1; TEST_ASSERT_SUCCESS_ERRNO ( zmq_setsockopt (from, ZMQ_DELAY_ATTACH_ON_CONNECT, &val, sizeof (val))); // Connect to the invalid socket TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (from, "tipc://{5561,0}@0.0.0")); // Connect to the valid socket TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (from, "tipc://{5560,0}@0.0.0")); // Send 10 messages, all should be routed to the connected pipe const int send_count = 10; for (int i = 0; i < send_count; ++i) { send_string_expect_success (from, "Hello", 0); } int timeout = SETTLE_TIME; TEST_ASSERT_SUCCESS_ERRNO ( zmq_setsockopt (to, ZMQ_RCVTIMEO, &timeout, sizeof (int))); int seen = 0; while (true) { char buffer[16]; int rc = zmq_recv (to, &buffer, sizeof (buffer), 0); if (rc == -1) { TEST_ASSERT_EQUAL_INT (EAGAIN, zmq_errno ()); break; // Break when we didn't get a message } seen++; } TEST_ASSERT_EQUAL_INT (send_count, seen); test_context_socket_close (from); test_context_socket_close (to); }
void test_router_2_router (bool named_) { char buff[256]; const char msg[] = "hi 1"; const int zero = 0; char my_endpoint[MAX_SOCKET_STRING]; // Create bind socket. void *rbind = test_context_socket (ZMQ_ROUTER); TEST_ASSERT_SUCCESS_ERRNO ( zmq_setsockopt (rbind, ZMQ_LINGER, &zero, sizeof (zero))); bind_loopback_ipv4 (rbind, my_endpoint, sizeof my_endpoint); // Create connection socket. void *rconn1 = test_context_socket (ZMQ_ROUTER); TEST_ASSERT_SUCCESS_ERRNO ( zmq_setsockopt (rconn1, ZMQ_LINGER, &zero, sizeof (zero))); // If we're in named mode, set some identities. if (named_) { TEST_ASSERT_SUCCESS_ERRNO ( zmq_setsockopt (rbind, ZMQ_ROUTING_ID, x_routing_id, 1)); TEST_ASSERT_SUCCESS_ERRNO ( zmq_setsockopt (rconn1, ZMQ_ROUTING_ID, y_routing_id, 1)); } // Make call to connect using a connect_routing_id. TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (rconn1, ZMQ_CONNECT_ROUTING_ID, rconn1routing_id, strlen (rconn1routing_id))); TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (rconn1, my_endpoint)); /* Uncomment to test assert on duplicate routing id // Test duplicate connect attempt. TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (rconn1, ZMQ_CONNECT_ROUTING_ID, rconn1routing_id, strlen (rconn1routing_id))); TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (rconn1, bindip)); */ // Send some data. send_string_expect_success (rconn1, rconn1routing_id, ZMQ_SNDMORE); send_string_expect_success (rconn1, msg, 0); // Receive the name. const int routing_id_len = zmq_recv (rbind, buff, 256, 0); if (named_) { TEST_ASSERT_EQUAL_INT (strlen (y_routing_id), routing_id_len); TEST_ASSERT_EQUAL_STRING_LEN (y_routing_id, buff, routing_id_len); } else { TEST_ASSERT_TRUE (routing_id_len && 0 == buff[0]); } // Receive the data. recv_string_expect_success (rbind, msg, 0); // Send some data back. const int ret = zmq_send (rbind, buff, routing_id_len, ZMQ_SNDMORE); TEST_ASSERT_EQUAL_INT (routing_id_len, ret); send_string_expect_success (rbind, "ok", 0); // If bound socket identity naming a problem, we'll likely see something funky here. recv_string_expect_success (rconn1, rconn1routing_id, 0); recv_string_expect_success (rconn1, "ok", 0); TEST_ASSERT_SUCCESS_ERRNO (zmq_unbind (rbind, my_endpoint)); test_context_socket_close (rbind); test_context_socket_close (rconn1); }
void test_router_2_router_while_receiving () { char buff[256]; const char msg[] = "hi 1"; const int zero = 0; char x_endpoint[MAX_SOCKET_STRING]; char z_endpoint[MAX_SOCKET_STRING]; // Create xbind socket. void *xbind = test_context_socket (ZMQ_ROUTER); TEST_ASSERT_SUCCESS_ERRNO ( zmq_setsockopt (xbind, ZMQ_LINGER, &zero, sizeof (zero))); bind_loopback_ipv4 (xbind, x_endpoint, sizeof x_endpoint); // Create zbind socket. void *zbind = test_context_socket (ZMQ_ROUTER); TEST_ASSERT_SUCCESS_ERRNO ( zmq_setsockopt (zbind, ZMQ_LINGER, &zero, sizeof (zero))); bind_loopback_ipv4 (zbind, z_endpoint, sizeof z_endpoint); // Create connection socket. void *yconn = test_context_socket (ZMQ_ROUTER); TEST_ASSERT_SUCCESS_ERRNO ( zmq_setsockopt (yconn, ZMQ_LINGER, &zero, sizeof (zero))); // set identities for each socket TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt ( xbind, ZMQ_ROUTING_ID, x_routing_id, strlen (x_routing_id))); TEST_ASSERT_SUCCESS_ERRNO ( zmq_setsockopt (yconn, ZMQ_ROUTING_ID, y_routing_id, 2)); TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt ( zbind, ZMQ_ROUTING_ID, z_routing_id, strlen (z_routing_id))); // Connect Y to X using a routing id TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt ( yconn, ZMQ_CONNECT_ROUTING_ID, x_routing_id, strlen (x_routing_id))); TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (yconn, x_endpoint)); // Send some data from Y to X. send_string_expect_success (yconn, x_routing_id, ZMQ_SNDMORE); send_string_expect_success (yconn, msg, 0); // wait for the Y->X message to be received msleep (SETTLE_TIME); // Now X tries to connect to Z and send a message TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt ( xbind, ZMQ_CONNECT_ROUTING_ID, z_routing_id, strlen (z_routing_id))); TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (xbind, z_endpoint)); // Try to send some data from X to Z. send_string_expect_success (xbind, z_routing_id, ZMQ_SNDMORE); send_string_expect_success (xbind, msg, 0); // wait for the X->Z message to be received (so that our non-blocking check will actually // fail if the message is routed to Y) msleep (SETTLE_TIME); // nothing should have been received on the Y socket TEST_ASSERT_FAILURE_ERRNO (EAGAIN, zmq_recv (yconn, buff, 256, ZMQ_DONTWAIT)); // the message should have been received on the Z socket recv_string_expect_success (zbind, x_routing_id, 0); recv_string_expect_success (zbind, msg, 0); TEST_ASSERT_SUCCESS_ERRNO (zmq_unbind (xbind, x_endpoint)); TEST_ASSERT_SUCCESS_ERRNO (zmq_unbind (zbind, z_endpoint)); test_context_socket_close (yconn); test_context_socket_close (xbind); test_context_socket_close (zbind); }
int test_blocking (int send_hwm_, int msg_cnt_, const char *endpoint) { size_t len = SOCKET_STRING_LEN; char pub_endpoint[SOCKET_STRING_LEN]; // Set up bind socket void *pub_socket = test_context_socket (ZMQ_XPUB); TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (pub_socket, endpoint)); TEST_ASSERT_SUCCESS_ERRNO ( zmq_getsockopt (pub_socket, ZMQ_LAST_ENDPOINT, pub_endpoint, &len)); // Set up connect socket void *sub_socket = test_context_socket (ZMQ_SUB); TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sub_socket, pub_endpoint)); //set a hwm on publisher TEST_ASSERT_SUCCESS_ERRNO ( zmq_setsockopt (pub_socket, ZMQ_SNDHWM, &send_hwm_, sizeof (send_hwm_))); int wait = 1; TEST_ASSERT_SUCCESS_ERRNO ( zmq_setsockopt (pub_socket, ZMQ_XPUB_NODROP, &wait, sizeof (wait))); int timeout_ms = 10; TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt ( sub_socket, ZMQ_RCVTIMEO, &timeout_ms, sizeof (timeout_ms))); TEST_ASSERT_SUCCESS_ERRNO ( zmq_setsockopt (sub_socket, ZMQ_SUBSCRIBE, 0, 0)); // Wait before starting TX operations till 1 subscriber has subscribed // (in this test there's 1 subscriber only) const char subscription_to_all_topics[] = {1, 0}; recv_string_expect_success (pub_socket, subscription_to_all_topics, 0); // Send until we block int send_count = 0; int recv_count = 0; int blocked_count = 0; int is_termination = 0; while (send_count < msg_cnt_) { const int rc = zmq_send (pub_socket, NULL, 0, ZMQ_DONTWAIT); if (rc == 0) { ++send_count; } else if (-1 == rc) { // if the PUB socket blocks due to HWM, errno should be EAGAIN: blocked_count++; TEST_ASSERT_EQUAL_INT (EAGAIN, errno); recv_count += receive (sub_socket, &is_termination); } } // if send_hwm_ < msg_cnt_, we should block at least once: TEST_ASSERT (blocked_count > 0); // dequeue SUB socket again, to make sure XPUB has space to send the termination message recv_count += receive (sub_socket, &is_termination); // send termination message send_string_expect_success (pub_socket, "end", 0); // now block on the SUB side till we get the termination message while (is_termination == 0) recv_count += receive (sub_socket, &is_termination); // remove termination message from the count: recv_count--; TEST_ASSERT_EQUAL_INT (send_count, recv_count); // Clean up test_context_socket_close (sub_socket); test_context_socket_close (pub_socket); return recv_count; }
void test_xpub_verboser_two_subs () { void *pub, *sub0, *sub1; create_xpub_with_2_subs (&pub, &sub0, &sub1); create_duplicate_subscription (pub, sub0, sub1); // Unsubscribe for A, this time it exists in XPUB TEST_ASSERT_SUCCESS_ERRNO ( zmq_setsockopt (sub0, ZMQ_UNSUBSCRIBE, topic_a, 1)); // sub1 is still subscribed, so no notification TEST_ASSERT_FAILURE_ERRNO (EAGAIN, zmq_recv (pub, NULL, 0, ZMQ_DONTWAIT)); // Unsubscribe the second socket to trigger the notification TEST_ASSERT_SUCCESS_ERRNO ( zmq_setsockopt (sub1, ZMQ_UNSUBSCRIBE, topic_a, 1)); // Receive unsubscriptions since all sockets are gone recv_array_expect_success (pub, unsubscribe_a_msg, 0); // Make really sure there is only one notification TEST_ASSERT_FAILURE_ERRNO (EAGAIN, zmq_recv (pub, NULL, 0, ZMQ_DONTWAIT)); int verbose = 1; TEST_ASSERT_SUCCESS_ERRNO ( zmq_setsockopt (pub, ZMQ_XPUB_VERBOSER, &verbose, sizeof (int))); // Subscribe socket for A again TEST_ASSERT_SUCCESS_ERRNO ( zmq_setsockopt (sub0, ZMQ_SUBSCRIBE, topic_a, 1)); // Subscribe socket for A again TEST_ASSERT_SUCCESS_ERRNO ( zmq_setsockopt (sub1, ZMQ_SUBSCRIBE, topic_a, 1)); // Receive subscriptions from subscriber, did not exist anymore recv_array_expect_success (pub, subscribe_a_msg, 0); // VERBOSER is set, so subs from both sockets are received recv_array_expect_success (pub, subscribe_a_msg, 0); // Sending A message to make sure everything still works send_string_expect_success (pub, topic_a, 0); recv_string_expect_success (sub0, topic_a, 0); recv_string_expect_success (sub1, topic_a, 0); // Unsubscribe for A TEST_ASSERT_SUCCESS_ERRNO ( zmq_setsockopt (sub1, ZMQ_UNSUBSCRIBE, topic_a, 1)); // Receive unsubscriptions from first subscriber due to VERBOSER recv_array_expect_success (pub, unsubscribe_a_msg, 0); // Unsubscribe for A again from the other socket TEST_ASSERT_SUCCESS_ERRNO ( zmq_setsockopt (sub0, ZMQ_UNSUBSCRIBE, topic_a, 1)); // Receive unsubscriptions from first subscriber due to VERBOSER recv_array_expect_success (pub, unsubscribe_a_msg, 0); // Unsubscribe again to make sure it gets filtered now TEST_ASSERT_SUCCESS_ERRNO ( zmq_setsockopt (sub1, ZMQ_UNSUBSCRIBE, topic_a, 1)); // Unmatched, so XSUB filters even with VERBOSER TEST_ASSERT_FAILURE_ERRNO (EAGAIN, zmq_recv (pub, NULL, 0, ZMQ_DONTWAIT)); // Clean up. test_context_socket_close (pub); test_context_socket_close (sub0); test_context_socket_close (sub1); }
void test_xpub_verboser_one_sub () { // Create a publisher void *pub = test_context_socket (ZMQ_XPUB); TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (pub, test_endpoint)); // Create a subscriber void *sub = test_context_socket (ZMQ_SUB); TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sub, test_endpoint)); // Unsubscribe for A, does not exist yet TEST_ASSERT_SUCCESS_ERRNO ( zmq_setsockopt (sub, ZMQ_UNSUBSCRIBE, topic_a, 1)); // Does not exist, so it will be filtered out by XSUB TEST_ASSERT_FAILURE_ERRNO (EAGAIN, zmq_recv (pub, NULL, 0, ZMQ_DONTWAIT)); // Subscribe for A TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (sub, ZMQ_SUBSCRIBE, topic_a, 1)); // Receive subscriptions from subscriber recv_array_expect_success (pub, subscribe_a_msg, 0); // Subscribe again for A again, XSUB will increase refcount TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (sub, ZMQ_SUBSCRIBE, topic_a, 1)); // This time it is duplicated, so it will be filtered out by XPUB TEST_ASSERT_FAILURE_ERRNO (EAGAIN, zmq_recv (pub, NULL, 0, ZMQ_DONTWAIT)); // Unsubscribe for A, this time it exists in XPUB TEST_ASSERT_SUCCESS_ERRNO ( zmq_setsockopt (sub, ZMQ_UNSUBSCRIBE, topic_a, 1)); // XSUB refcounts and will not actually send unsub to PUB until the number // of unsubs match the earlier subs TEST_ASSERT_SUCCESS_ERRNO ( zmq_setsockopt (sub, ZMQ_UNSUBSCRIBE, topic_a, 1)); // Receive unsubscriptions from subscriber recv_array_expect_success (pub, unsubscribe_a_msg, 0); // XSUB only sends the last and final unsub, so XPUB will only receive 1 TEST_ASSERT_FAILURE_ERRNO (EAGAIN, zmq_recv (pub, NULL, 0, ZMQ_DONTWAIT)); // Unsubscribe for A, does not exist anymore TEST_ASSERT_SUCCESS_ERRNO ( zmq_setsockopt (sub, ZMQ_UNSUBSCRIBE, topic_a, 1)); // Does not exist, so it will be filtered out by XSUB TEST_ASSERT_FAILURE_ERRNO (EAGAIN, zmq_recv (pub, NULL, 0, ZMQ_DONTWAIT)); int verbose = 1; TEST_ASSERT_SUCCESS_ERRNO ( zmq_setsockopt (pub, ZMQ_XPUB_VERBOSER, &verbose, sizeof (int))); // Subscribe socket for A again TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (sub, ZMQ_SUBSCRIBE, topic_a, 1)); // Receive subscriptions from subscriber, did not exist anymore recv_array_expect_success (pub, subscribe_a_msg, 0); // Sending A message to make sure everything still works send_string_expect_success (pub, topic_a, 0); recv_string_expect_success (sub, topic_a, 0); // Unsubscribe for A, this time it exists TEST_ASSERT_SUCCESS_ERRNO ( zmq_setsockopt (sub, ZMQ_UNSUBSCRIBE, topic_a, 1)); // Receive unsubscriptions from subscriber recv_array_expect_success (pub, unsubscribe_a_msg, 0); // Unsubscribe for A again, it does not exist anymore so XSUB will filter TEST_ASSERT_SUCCESS_ERRNO ( zmq_setsockopt (sub, ZMQ_UNSUBSCRIBE, topic_a, 1)); // XSUB only sends unsub if it matched it in its trie, IOW: it will only // send it if it existed in the first place even with XPUB_VERBBOSER TEST_ASSERT_FAILURE_ERRNO (EAGAIN, zmq_recv (pub, NULL, 0, ZMQ_DONTWAIT)); // Clean up. test_context_socket_close (pub); test_context_socket_close (sub); }