int zre_msg_send_leave ( void *output, uint16_t sequence, const char *group, byte status) { zre_msg_t *self = zre_msg_new (ZRE_MSG_LEAVE); zre_msg_set_sequence (self, sequence); zre_msg_set_group (self, group); zre_msg_set_status (self, status); return zre_msg_send (&self, output); }
int zre_msg_send_join ( void *output, uint16_t sequence, char *group, byte status) { zre_msg_t *self = zre_msg_new (ZRE_MSG_JOIN); zre_msg_set_sequence (self, sequence); zre_msg_set_group (self, group); zre_msg_set_status (self, status); return zre_msg_send (&self, output); }
int zre_msg_send_shout ( void *output, uint16_t sequence, char *group, zframe_t *content) { zre_msg_t *self = zre_msg_new (ZRE_MSG_SHOUT); zre_msg_set_sequence (self, sequence); zre_msg_set_group (self, group); zre_msg_set_content (self, zframe_dup (content)); return zre_msg_send (&self, output); }
static int zyre_node_recv_api (zyre_node_t *self) { // Get the whole message off the pipe in one go zmsg_t *request = zmsg_recv (self->pipe); char *command = zmsg_popstr (request); if (!command) return -1; // Interrupted if (streq (command, "SET")) { char *name = zmsg_popstr (request); char *value = zmsg_popstr (request); zhash_update (self->headers, name, value); zstr_free (&name); zstr_free (&value); } else if (streq (command, "START")) { zyre_node_start (self); zstr_send (self->pipe, "OK"); } else if (streq (command, "STOP")) { zyre_node_stop (self); zstr_send (self->pipe, "OK"); } else if (streq (command, "WHISPER")) { // Get peer to send message to char *identity = zmsg_popstr (request); zyre_peer_t *peer = (zyre_peer_t *) zhash_lookup (self->peers, identity); // Send frame on out to peer's mailbox, drop message // if peer doesn't exist (may have been destroyed) if (peer) { zre_msg_t *msg = zre_msg_new (ZRE_MSG_WHISPER); zre_msg_set_content (msg, request); zyre_peer_send (peer, &msg); request = NULL; } zstr_free (&identity); } else if (streq (command, "SHOUT")) { // Get group to send message to char *name = zmsg_popstr (request); zyre_group_t *group = (zyre_group_t *) zhash_lookup (self->peer_groups, name); if (group) { zre_msg_t *msg = zre_msg_new (ZRE_MSG_SHOUT); zre_msg_set_group (msg, name); zre_msg_set_content (msg, request); zyre_group_send (group, &msg); request = NULL; } zstr_free (&name); } else if (streq (command, "JOIN")) { char *name = zmsg_popstr (request); zyre_group_t *group = (zyre_group_t *) zhash_lookup (self->own_groups, name); if (!group) { // Only send if we're not already in group group = zyre_group_new (name, self->own_groups); zre_msg_t *msg = zre_msg_new (ZRE_MSG_JOIN); zre_msg_set_group (msg, name); // Update status before sending command zre_msg_set_status (msg, ++(self->status)); zhash_foreach (self->peers, zyre_node_send_peer, msg); zre_msg_destroy (&msg); zyre_log_info (self->log, ZRE_LOG_MSG_EVENT_JOIN, NULL, name); } zstr_free (&name); } else if (streq (command, "LEAVE")) { char *name = zmsg_popstr (request); zyre_group_t *group = (zyre_group_t *) zhash_lookup (self->own_groups, name); if (group) { // Only send if we are actually in group zre_msg_t *msg = zre_msg_new (ZRE_MSG_LEAVE); zre_msg_set_group (msg, name); // Update status before sending command zre_msg_set_status (msg, ++(self->status)); zhash_foreach (self->peers, zyre_node_send_peer, msg); zre_msg_destroy (&msg); zhash_delete (self->own_groups, name); zyre_log_info (self->log, ZRE_LOG_MSG_EVENT_LEAVE, NULL, name); } zstr_free (&name); } else if (streq (command, "TERMINATE")) { self->terminated = true; zstr_send (self->pipe, "OK"); } zstr_free (&command); zmsg_destroy (&request); return 0; }
static void zyre_node_recv_api (zyre_node_t *self) { // Get the whole message off the pipe in one go zmsg_t *request = zmsg_recv (self->pipe); if (!request) return; // Interrupted char *command = zmsg_popstr (request); if (streq (command, "UUID")) zstr_send (self->pipe, zuuid_str (self->uuid)); else if (streq (command, "NAME")) zstr_send (self->pipe, self->name); else if (streq (command, "SET NAME")) { free (self->name); self->name = zmsg_popstr (request); assert (self->name); } else if (streq (command, "SET HEADER")) { char *name = zmsg_popstr (request); char *value = zmsg_popstr (request); zhash_update (self->headers, name, value); zstr_free (&name); zstr_free (&value); } else if (streq (command, "SET VERBOSE")) self->verbose = true; else if (streq (command, "SET PORT")) { char *value = zmsg_popstr (request); self->beacon_port = atoi (value); zstr_free (&value); } else if (streq (command, "SET EVASIVE TIMEOUT")) { char *value = zmsg_popstr (request); self->evasive_timeout = atoi (value); zstr_free (&value); } else if (streq (command, "SET EXPIRED TIMEOUT")) { char *value = zmsg_popstr (request); self->expired_timeout = atoi (value); zstr_free (&value); } else if (streq (command, "SET INTERVAL")) { char *value = zmsg_popstr (request); self->interval = atol (value); zstr_free (&value); } else if (streq (command, "SET ENDPOINT")) { zyre_node_gossip_start (self); char *endpoint = zmsg_popstr (request); if (zsock_bind (self->inbox, "%s", endpoint) != -1) { zstr_free (&self->endpoint); self->endpoint = endpoint; zsock_signal (self->pipe, 0); } else { zstr_free (&endpoint); zsock_signal (self->pipe, 1); } } else if (streq (command, "GOSSIP BIND")) { zyre_node_gossip_start (self); zstr_free (&self->gossip_bind); self->gossip_bind = zmsg_popstr (request); zstr_sendx (self->gossip, "BIND", self->gossip_bind, NULL); } else if (streq (command, "GOSSIP CONNECT")) { zyre_node_gossip_start (self); zstr_free (&self->gossip_connect); self->gossip_connect = zmsg_popstr (request); zstr_sendx (self->gossip, "CONNECT", self->gossip_connect, NULL); } else if (streq (command, "START")) zsock_signal (self->pipe, zyre_node_start (self)); else if (streq (command, "STOP")) zsock_signal (self->pipe, zyre_node_stop (self)); else if (streq (command, "WHISPER")) { // Get peer to send message to char *identity = zmsg_popstr (request); zyre_peer_t *peer = (zyre_peer_t *) zhash_lookup (self->peers, identity); // Send frame on out to peer's mailbox, drop message // if peer doesn't exist (may have been destroyed) if (peer) { zre_msg_t *msg = zre_msg_new (ZRE_MSG_WHISPER); zre_msg_set_content (msg, &request); zyre_peer_send (peer, &msg); } zstr_free (&identity); } else if (streq (command, "SHOUT")) { // Get group to send message to char *name = zmsg_popstr (request); zyre_group_t *group = (zyre_group_t *) zhash_lookup (self->peer_groups, name); if (group) { zre_msg_t *msg = zre_msg_new (ZRE_MSG_SHOUT); zre_msg_set_group (msg, name); zre_msg_set_content (msg, &request); zyre_group_send (group, &msg); } zstr_free (&name); } else if (streq (command, "JOIN")) { char *name = zmsg_popstr (request); if (!zlist_exists (self->own_groups, name)) { void *item; // Only send if we're not already in group zlist_append (self->own_groups, name); zre_msg_t *msg = zre_msg_new (ZRE_MSG_JOIN); zre_msg_set_group (msg, name); // Update status before sending command zre_msg_set_status (msg, ++(self->status)); for (item = zhash_first (self->peers); item != NULL; item = zhash_next (self->peers)) zyre_node_send_peer (zhash_cursor (self->peers), item, msg); zre_msg_destroy (&msg); if (self->verbose) zsys_info ("(%s) JOIN group=%s", self->name, name); } zstr_free (&name); } else if (streq (command, "LEAVE")) { char *name = zmsg_popstr (request); if (zlist_exists (self->own_groups, name)) { void *item; // Only send if we are actually in group zre_msg_t *msg = zre_msg_new (ZRE_MSG_LEAVE); zre_msg_set_group (msg, name); // Update status before sending command zre_msg_set_status (msg, ++(self->status)); for (item = zhash_first (self->peers); item != NULL; item = zhash_next (self->peers)) zyre_node_send_peer (zhash_cursor (self->peers), item, msg); zre_msg_destroy (&msg); zlist_remove (self->own_groups, name); if (self->verbose) zsys_info ("(%s) LEAVE group=%s", self->name, name); } zstr_free (&name); } else if (streq (command, "PEERS")) zsock_send (self->pipe, "p", zhash_keys (self->peers)); else if (streq (command, "GROUP PEERS")) { char *name = zmsg_popstr (request); zyre_group_t *group = (zyre_group_t *) zhash_lookup (self->peer_groups, name); if (group) zsock_send (self->pipe, "p", zyre_group_peers (group)); else zsock_send (self->pipe, "p", NULL); zstr_free (&name); } else if (streq (command, "PEER ENDPOINT")) { char *uuid = zmsg_popstr (request); zyre_peer_t *peer = (zyre_peer_t *) zhash_lookup (self->peers, uuid); assert (peer); zsock_send (self->pipe, "s", zyre_peer_endpoint (peer)); zstr_free (&uuid); } else if (streq (command, "PEER NAME")) { char *uuid = zmsg_popstr (request); zyre_peer_t *peer = (zyre_peer_t *) zhash_lookup (self->peers, uuid); assert (peer); zsock_send (self->pipe, "s", zyre_peer_name (peer)); zstr_free (&uuid); } else if (streq (command, "PEER HEADER")) { char *uuid = zmsg_popstr (request); char *key = zmsg_popstr (request); zyre_peer_t *peer = (zyre_peer_t *) zhash_lookup (self->peers, uuid); if (!peer) zstr_send (self->pipe, ""); else zstr_send (self->pipe, zyre_peer_header (peer, key, NULL)); zstr_free (&uuid); zstr_free (&key); } else if (streq (command, "PEER GROUPS")) zsock_send (self->pipe, "p", zhash_keys (self->peer_groups)); else if (streq (command, "OWN GROUPS")) zsock_send (self->pipe, "p", zlist_dup (self->own_groups)); else if (streq (command, "DUMP")) zyre_node_dump (self); else if (streq (command, "$TERM")) self->terminated = true; else { zsys_error ("invalid command '%s'", command); assert (false); } zstr_free (&command); zmsg_destroy (&request); }
int zre_msg_test (bool verbose) { printf (" * zre_msg: "); // @selftest // Simple create/destroy test zre_msg_t *self = zre_msg_new (0); assert (self); zre_msg_destroy (&self); // Create pair of sockets we can send through zctx_t *ctx = zctx_new (); assert (ctx); void *output = zsocket_new (ctx, ZMQ_DEALER); assert (output); zsocket_bind (output, "inproc://selftest"); void *input = zsocket_new (ctx, ZMQ_ROUTER); assert (input); zsocket_connect (input, "inproc://selftest"); // Encode/send/decode and verify each message type int instance; zre_msg_t *copy; self = zre_msg_new (ZRE_MSG_HELLO); // Check that _dup works on empty message copy = zre_msg_dup (self); assert (copy); zre_msg_destroy (©); zre_msg_set_sequence (self, 123); zre_msg_set_ipaddress (self, "Life is short but Now lasts for ever"); zre_msg_set_mailbox (self, 123); zre_msg_groups_append (self, "Name: %s", "Brutus"); zre_msg_groups_append (self, "Age: %d", 43); zre_msg_set_status (self, 123); zre_msg_headers_insert (self, "Name", "Brutus"); zre_msg_headers_insert (self, "Age", "%d", 43); // Send twice from same object zre_msg_send_again (self, output); zre_msg_send (&self, output); for (instance = 0; instance < 2; instance++) { self = zre_msg_recv (input); assert (self); assert (zre_msg_routing_id (self)); assert (zre_msg_sequence (self) == 123); assert (streq (zre_msg_ipaddress (self), "Life is short but Now lasts for ever")); assert (zre_msg_mailbox (self) == 123); assert (zre_msg_groups_size (self) == 2); assert (streq (zre_msg_groups_first (self), "Name: Brutus")); assert (streq (zre_msg_groups_next (self), "Age: 43")); assert (zre_msg_status (self) == 123); assert (zre_msg_headers_size (self) == 2); assert (streq (zre_msg_headers_string (self, "Name", "?"), "Brutus")); assert (zre_msg_headers_number (self, "Age", 0) == 43); zre_msg_destroy (&self); } self = zre_msg_new (ZRE_MSG_WHISPER); // Check that _dup works on empty message copy = zre_msg_dup (self); assert (copy); zre_msg_destroy (©); zre_msg_set_sequence (self, 123); zmsg_t *whisper_content = zmsg_new (); zre_msg_set_content (self, &whisper_content); zmsg_addstr (zre_msg_content (self), "Hello, World"); // Send twice from same object zre_msg_send_again (self, output); zre_msg_send (&self, output); for (instance = 0; instance < 2; instance++) { self = zre_msg_recv (input); assert (self); assert (zre_msg_routing_id (self)); assert (zre_msg_sequence (self) == 123); assert (zmsg_size (zre_msg_content (self)) == 1); zre_msg_destroy (&self); } self = zre_msg_new (ZRE_MSG_SHOUT); // Check that _dup works on empty message copy = zre_msg_dup (self); assert (copy); zre_msg_destroy (©); zre_msg_set_sequence (self, 123); zre_msg_set_group (self, "Life is short but Now lasts for ever"); zmsg_t *shout_content = zmsg_new (); zre_msg_set_content (self, &shout_content); zmsg_addstr (zre_msg_content (self), "Hello, World"); // Send twice from same object zre_msg_send_again (self, output); zre_msg_send (&self, output); for (instance = 0; instance < 2; instance++) { self = zre_msg_recv (input); assert (self); assert (zre_msg_routing_id (self)); assert (zre_msg_sequence (self) == 123); assert (streq (zre_msg_group (self), "Life is short but Now lasts for ever")); assert (zmsg_size (zre_msg_content (self)) == 1); zre_msg_destroy (&self); } self = zre_msg_new (ZRE_MSG_JOIN); // Check that _dup works on empty message copy = zre_msg_dup (self); assert (copy); zre_msg_destroy (©); zre_msg_set_sequence (self, 123); zre_msg_set_group (self, "Life is short but Now lasts for ever"); zre_msg_set_status (self, 123); // Send twice from same object zre_msg_send_again (self, output); zre_msg_send (&self, output); for (instance = 0; instance < 2; instance++) { self = zre_msg_recv (input); assert (self); assert (zre_msg_routing_id (self)); assert (zre_msg_sequence (self) == 123); assert (streq (zre_msg_group (self), "Life is short but Now lasts for ever")); assert (zre_msg_status (self) == 123); zre_msg_destroy (&self); } self = zre_msg_new (ZRE_MSG_LEAVE); // Check that _dup works on empty message copy = zre_msg_dup (self); assert (copy); zre_msg_destroy (©); zre_msg_set_sequence (self, 123); zre_msg_set_group (self, "Life is short but Now lasts for ever"); zre_msg_set_status (self, 123); // Send twice from same object zre_msg_send_again (self, output); zre_msg_send (&self, output); for (instance = 0; instance < 2; instance++) { self = zre_msg_recv (input); assert (self); assert (zre_msg_routing_id (self)); assert (zre_msg_sequence (self) == 123); assert (streq (zre_msg_group (self), "Life is short but Now lasts for ever")); assert (zre_msg_status (self) == 123); zre_msg_destroy (&self); } self = zre_msg_new (ZRE_MSG_PING); // Check that _dup works on empty message copy = zre_msg_dup (self); assert (copy); zre_msg_destroy (©); zre_msg_set_sequence (self, 123); // Send twice from same object zre_msg_send_again (self, output); zre_msg_send (&self, output); for (instance = 0; instance < 2; instance++) { self = zre_msg_recv (input); assert (self); assert (zre_msg_routing_id (self)); assert (zre_msg_sequence (self) == 123); zre_msg_destroy (&self); } self = zre_msg_new (ZRE_MSG_PING_OK); // Check that _dup works on empty message copy = zre_msg_dup (self); assert (copy); zre_msg_destroy (©); zre_msg_set_sequence (self, 123); // Send twice from same object zre_msg_send_again (self, output); zre_msg_send (&self, output); for (instance = 0; instance < 2; instance++) { self = zre_msg_recv (input); assert (self); assert (zre_msg_routing_id (self)); assert (zre_msg_sequence (self) == 123); zre_msg_destroy (&self); } zctx_destroy (&ctx); // @end printf ("OK\n"); return 0; }
static int zyre_node_recv_api (zyre_node_t *self) { // Get the whole message off the pipe in one go zmsg_t *request = zmsg_recv (self->pipe); char *command = zmsg_popstr (request); if (!command) return -1; // Interrupted if (streq (command, "SET NAME")) { free (self->name); self->name = zmsg_popstr (request); assert (self->name); } else if (streq (command, "SET HEADER")) { char *name = zmsg_popstr (request); char *value = zmsg_popstr (request); zhash_update (self->headers, name, value); zstr_free (&name); zstr_free (&value); } else if (streq (command, "SET VERBOSE")) self->verbose = true; else if (streq (command, "SET PORT")) { char *value = zmsg_popstr (request); self->beacon_port = atoi (value); zstr_free (&value); } else if (streq (command, "SET INTERVAL")) { char *value = zmsg_popstr (request); self->interval = atol (value); zstr_free (&value); } else if (streq (command, "UUID")) zstr_send (self->pipe, zuuid_str (self->uuid)); else if (streq (command, "NAME")) zstr_send (self->pipe, self->name); else if (streq (command, "BIND")) { char *endpoint = zmsg_popstr (request); zsock_signal (self->pipe, zyre_node_bind (self, endpoint)); zstr_free (&endpoint); } else if (streq (command, "CONNECT")) { char *endpoint = zmsg_popstr (request); zsock_signal (self->pipe, zyre_node_connect (self, endpoint)); zstr_free (&endpoint); } else if (streq (command, "START")) zsock_signal (self->pipe, zyre_node_start (self)); else if (streq (command, "STOP")) zsock_signal (self->pipe, zyre_node_stop (self)); else if (streq (command, "WHISPER")) { // Get peer to send message to char *identity = zmsg_popstr (request); zyre_peer_t *peer = (zyre_peer_t *) zhash_lookup (self->peers, identity); // Send frame on out to peer's mailbox, drop message // if peer doesn't exist (may have been destroyed) if (peer) { zre_msg_t *msg = zre_msg_new (ZRE_MSG_WHISPER); zre_msg_set_content (msg, &request); zyre_peer_send (peer, &msg); } zstr_free (&identity); } else if (streq (command, "SHOUT")) { // Get group to send message to char *name = zmsg_popstr (request); zyre_group_t *group = (zyre_group_t *) zhash_lookup (self->peer_groups, name); if (group) { zre_msg_t *msg = zre_msg_new (ZRE_MSG_SHOUT); zre_msg_set_group (msg, name); zre_msg_set_content (msg, &request); zyre_group_send (group, &msg); } zstr_free (&name); } else if (streq (command, "JOIN")) { char *name = zmsg_popstr (request); zyre_group_t *group = (zyre_group_t *) zhash_lookup (self->own_groups, name); if (!group) { // Only send if we're not already in group group = zyre_group_new (name, self->own_groups); zre_msg_t *msg = zre_msg_new (ZRE_MSG_JOIN); zre_msg_set_group (msg, name); // Update status before sending command zre_msg_set_status (msg, ++(self->status)); zhash_foreach (self->peers, zyre_node_send_peer, msg); zre_msg_destroy (&msg); if (self->verbose) zsys_info ("(%s) JOIN group=%s", self->name, name); } zstr_free (&name); } else if (streq (command, "LEAVE")) { char *name = zmsg_popstr (request); zyre_group_t *group = (zyre_group_t *) zhash_lookup (self->own_groups, name); if (group) { // Only send if we are actually in group zre_msg_t *msg = zre_msg_new (ZRE_MSG_LEAVE); zre_msg_set_group (msg, name); // Update status before sending command zre_msg_set_status (msg, ++(self->status)); zhash_foreach (self->peers, zyre_node_send_peer, msg); zre_msg_destroy (&msg); zhash_delete (self->own_groups, name); if (self->verbose) zsys_info ("(%s) LEAVE group=%s", self->name, name); } zstr_free (&name); } else if (streq (command, "DUMP")) zyre_node_dump (self); else if (streq (command, "$TERM")) self->terminated = true; else { zsys_error ("invalid command '%s'\n", command); assert (false); } zstr_free (&command); zmsg_destroy (&request); return 0; }
int zre_msg_test (bool verbose) { printf (" * zre_msg: "); // @selftest // Simple create/destroy test zre_msg_t *self = zre_msg_new (0); assert (self); zre_msg_destroy (&self); // Create pair of sockets we can send through zctx_t *ctx = zctx_new (); assert (ctx); void *output = zsocket_new (ctx, ZMQ_DEALER); assert (output); zsocket_bind (output, "inproc://selftest"); void *input = zsocket_new (ctx, ZMQ_ROUTER); assert (input); zsocket_connect (input, "inproc://selftest"); // Encode/send/decode and verify each message type self = zre_msg_new (ZRE_MSG_HELLO); zre_msg_set_sequence (self, 123); zre_msg_set_ipaddress (self, "Life is short but Now lasts for ever"); zre_msg_set_mailbox (self, 123); zre_msg_groups_append (self, "Name: %s", "Brutus"); zre_msg_groups_append (self, "Age: %d", 43); zre_msg_set_status (self, 123); zre_msg_headers_insert (self, "Name", "Brutus"); zre_msg_headers_insert (self, "Age", "%d", 43); zre_msg_send (&self, output); self = zre_msg_recv (input); assert (self); assert (zre_msg_sequence (self) == 123); assert (streq (zre_msg_ipaddress (self), "Life is short but Now lasts for ever")); assert (zre_msg_mailbox (self) == 123); assert (zre_msg_groups_size (self) == 2); assert (streq (zre_msg_groups_first (self), "Name: Brutus")); assert (streq (zre_msg_groups_next (self), "Age: 43")); assert (zre_msg_status (self) == 123); assert (zre_msg_headers_size (self) == 2); assert (streq (zre_msg_headers_string (self, "Name", "?"), "Brutus")); assert (zre_msg_headers_number (self, "Age", 0) == 43); zre_msg_destroy (&self); self = zre_msg_new (ZRE_MSG_WHISPER); zre_msg_set_sequence (self, 123); zre_msg_set_content (self, zframe_new ("Captcha Diem", 12)); zre_msg_send (&self, output); self = zre_msg_recv (input); assert (self); assert (zre_msg_sequence (self) == 123); assert (zframe_streq (zre_msg_content (self), "Captcha Diem")); zre_msg_destroy (&self); self = zre_msg_new (ZRE_MSG_SHOUT); zre_msg_set_sequence (self, 123); zre_msg_set_group (self, "Life is short but Now lasts for ever"); zre_msg_set_content (self, zframe_new ("Captcha Diem", 12)); zre_msg_send (&self, output); self = zre_msg_recv (input); assert (self); assert (zre_msg_sequence (self) == 123); assert (streq (zre_msg_group (self), "Life is short but Now lasts for ever")); assert (zframe_streq (zre_msg_content (self), "Captcha Diem")); zre_msg_destroy (&self); self = zre_msg_new (ZRE_MSG_JOIN); zre_msg_set_sequence (self, 123); zre_msg_set_group (self, "Life is short but Now lasts for ever"); zre_msg_set_status (self, 123); zre_msg_send (&self, output); self = zre_msg_recv (input); assert (self); assert (zre_msg_sequence (self) == 123); assert (streq (zre_msg_group (self), "Life is short but Now lasts for ever")); assert (zre_msg_status (self) == 123); zre_msg_destroy (&self); self = zre_msg_new (ZRE_MSG_LEAVE); zre_msg_set_sequence (self, 123); zre_msg_set_group (self, "Life is short but Now lasts for ever"); zre_msg_set_status (self, 123); zre_msg_send (&self, output); self = zre_msg_recv (input); assert (self); assert (zre_msg_sequence (self) == 123); assert (streq (zre_msg_group (self), "Life is short but Now lasts for ever")); assert (zre_msg_status (self) == 123); zre_msg_destroy (&self); self = zre_msg_new (ZRE_MSG_PING); zre_msg_set_sequence (self, 123); zre_msg_send (&self, output); self = zre_msg_recv (input); assert (self); assert (zre_msg_sequence (self) == 123); zre_msg_destroy (&self); self = zre_msg_new (ZRE_MSG_PING_OK); zre_msg_set_sequence (self, 123); zre_msg_send (&self, output); self = zre_msg_recv (input); assert (self); assert (zre_msg_sequence (self) == 123); zre_msg_destroy (&self); zctx_destroy (&ctx); // @end printf ("OK\n"); return 0; }