zyre(3) ======= NAME ---- zyre - API wrapping one Zyre node SYNOPSIS -------- ---- // This is a draft class, and may change without notice. It is disabled in // stable builds by default. If you use this in applications, please ask // for it to be pushed to stable state. Use --enable-drafts to enable. #ifdef ZYRE_BUILD_DRAFT_API // *** Draft method, for development use, may change without warning *** // Constructor, creates a new Zyre node. Note that until you start the // node it is silent and invisible to other nodes on the network. // The node name is provided to other nodes during discovery. If you // specify NULL, Zyre generates a randomized node name from the UUID. ZYRE_EXPORT zyre_t * zyre_new (const char *name); // *** Draft method, for development use, may change without warning *** // Destructor, destroys a Zyre node. When you destroy a node, any // messages it is sending or receiving will be discarded. ZYRE_EXPORT void zyre_destroy (zyre_t **self_p); // *** Draft method, for development use, may change without warning *** // Return our node UUID string, after successful initialization ZYRE_EXPORT const char * zyre_uuid (zyre_t *self); // *** Draft method, for development use, may change without warning *** // Return our node name, after successful initialization ZYRE_EXPORT const char * zyre_name (zyre_t *self); // *** Draft method, for development use, may change without warning *** // Set node header; these are provided to other nodes during discovery // and come in each ENTER message. ZYRE_EXPORT void zyre_set_header (zyre_t *self, const char *name, const char *format, ...); // *** Draft method, for development use, may change without warning *** // Set verbose mode; this tells the node to log all traffic as well as // all major events. ZYRE_EXPORT void zyre_set_verbose (zyre_t *self); // *** Draft method, for development use, may change without warning *** // Set UDP beacon discovery port; defaults to 5670, this call overrides // that so you can create independent clusters on the same network, for // e.g. development vs. production. Has no effect after zyre_start(). ZYRE_EXPORT void zyre_set_port (zyre_t *self, int port_nbr); // *** Draft method, for development use, may change without warning *** // Set UDP beacon discovery interval, in milliseconds. Default is instant // beacon exploration followed by pinging every 1,000 msecs. ZYRE_EXPORT void zyre_set_interval (zyre_t *self, size_t interval); // *** Draft method, for development use, may change without warning *** // Set network interface for UDP beacons. If you do not set this, CZMQ will // choose an interface for you. On boxes with several interfaces you should // specify which one you want to use, or strange things can happen. ZYRE_EXPORT void zyre_set_interface (zyre_t *self, const char *value); // *** Draft method, for development use, may change without warning *** // By default, Zyre binds to an ephemeral TCP port and broadcasts the local // host name using UDP beaconing. When you call this method, Zyre will use // gossip discovery instead of UDP beaconing. You MUST set-up the gossip // service separately using zyre_gossip_bind() and _connect(). Note that the // endpoint MUST be valid for both bind and connect operations. You can use // inproc://, ipc://, or tcp:// transports (for tcp://, use an IP address // that is meaningful to remote as well as local nodes). Returns 0 if // the bind was successful, else -1. ZYRE_EXPORT int zyre_set_endpoint (zyre_t *self, const char *format, ...); // *** Draft method, for development use, may change without warning *** // Set-up gossip discovery of other nodes. At least one node in the cluster // must bind to a well-known gossip endpoint, so other nodes can connect to // it. Note that gossip endpoints are completely distinct from Zyre node // endpoints, and should not overlap (they can use the same transport). ZYRE_EXPORT void zyre_gossip_bind (zyre_t *self, const char *format, ...); // *** Draft method, for development use, may change without warning *** // Set-up gossip discovery of other nodes. A node may connect to multiple // other nodes, for redundancy paths. For details of the gossip network // design, see the CZMQ zgossip class. ZYRE_EXPORT void zyre_gossip_connect (zyre_t *self, const char *format, ...); // *** Draft method, for development use, may change without warning *** // Start node, after setting header values. When you start a node it // begins discovery and connection. Returns 0 if OK, -1 if it wasn't // possible to start the node. ZYRE_EXPORT int zyre_start (zyre_t *self); // *** Draft method, for development use, may change without warning *** // Stop node; this signals to other peers that this node will go away. // This is polite; however you can also just destroy the node without // stopping it. ZYRE_EXPORT void zyre_stop (zyre_t *self); // *** Draft method, for development use, may change without warning *** // Join a named group; after joining a group you can send messages to // the group and all Zyre nodes in that group will receive them. ZYRE_EXPORT int zyre_join (zyre_t *self, const char *group); // *** Draft method, for development use, may change without warning *** // Leave a group ZYRE_EXPORT int zyre_leave (zyre_t *self, const char *group); // *** Draft method, for development use, may change without warning *** // Receive next message from network; the message may be a control // message (ENTER, EXIT, JOIN, LEAVE) or data (WHISPER, SHOUT). // Returns zmsg_t object, or NULL if interrupted ZYRE_EXPORT zmsg_t * zyre_recv (zyre_t *self); // *** Draft method, for development use, may change without warning *** // Send message to single peer, specified as a UUID string // Destroys message after sending ZYRE_EXPORT int zyre_whisper (zyre_t *self, const char *peer, zmsg_t **msg_p); // *** Draft method, for development use, may change without warning *** // Send message to a named group // Destroys message after sending ZYRE_EXPORT int zyre_shout (zyre_t *self, const char *group, zmsg_t **msg_p); // *** Draft method, for development use, may change without warning *** // Send formatted string to a single peer specified as UUID string ZYRE_EXPORT int zyre_whispers (zyre_t *self, const char *peer, const char *format, ...); // *** Draft method, for development use, may change without warning *** // Send formatted string to a named group ZYRE_EXPORT int zyre_shouts (zyre_t *self, const char *group, const char *format, ...); // *** Draft method, for development use, may change without warning *** // Return zlist of current peer ids. // Caller owns return value and must destroy it when done. ZYRE_EXPORT zlist_t * zyre_peers (zyre_t *self); // *** Draft method, for development use, may change without warning *** // Return zlist of currently joined groups. // Caller owns return value and must destroy it when done. ZYRE_EXPORT zlist_t * zyre_own_groups (zyre_t *self); // *** Draft method, for development use, may change without warning *** // Return zlist of groups known through connected peers. // Caller owns return value and must destroy it when done. ZYRE_EXPORT zlist_t * zyre_peer_groups (zyre_t *self); // *** Draft method, for development use, may change without warning *** // Return the endpoint of a connected peer. // Caller owns return value and must destroy it when done. ZYRE_EXPORT char * zyre_peer_address (zyre_t *self, const char *peer); // *** Draft method, for development use, may change without warning *** // Return the value of a header of a conected peer. // Returns null if peer or key doesn't exits. // Caller owns return value and must destroy it when done. ZYRE_EXPORT char * zyre_peer_header_value (zyre_t *self, const char *peer, const char *name); // *** Draft method, for development use, may change without warning *** // Return socket for talking to the Zyre node, for polling ZYRE_EXPORT zsock_t * zyre_socket (zyre_t *self); // *** Draft method, for development use, may change without warning *** // Print zyre node information to stdout ZYRE_EXPORT void zyre_print (zyre_t *self); // *** Draft method, for development use, may change without warning *** // Return the Zyre version for run-time API detection ZYRE_EXPORT void zyre_version (int *major, int *minor, int *patch); // *** Draft method, for development use, may change without warning *** // Self test of this class. ZYRE_EXPORT void zyre_test (bool verbose); #endif // ZYRE_BUILD_DRAFT_API ---- DESCRIPTION ----------- Zyre does local area discovery and clustering. A Zyre node broadcasts UDP beacons, and connects to peers that it finds. This class wraps a Zyre node with a message-based API. All incoming events are zmsg_t messages delivered via the zyre_recv call. The first frame defines the type of the message, and following frames provide further values: ENTER fromnode name headers ipaddress:port a new peer has entered the network EVASIVE fromnode name a peer is being evasive (quiet for too long) EXIT fromnode name a peer has left the network JOIN fromnode name groupname a peer has joined a specific group LEAVE fromnode name groupname a peer has joined a specific group WHISPER fromnode name message a peer has sent this node a message SHOUT fromnode name groupname message a peer has sent one of our groups a message In SHOUT and WHISPER the message is zero or more frames, and can hold any ZeroMQ message. In ENTER, the headers frame contains a packed dictionary, see zhash_pack/unpack. To join or leave a group, use the zyre_join and zyre_leave methods. To set a header value, use the zyre_set_header method. To send a message to a single peer, use zyre_whisper. To send a message to a group, use zyre_shout. Todo: allow multipart contents EXAMPLE ------- .From zyre_test method ---- // We'll use inproc gossip discovery so that this works without networking int major, minor, patch; zyre_version (&major, &minor, &patch); assert (major == ZYRE_VERSION_MAJOR); assert (minor == ZYRE_VERSION_MINOR); assert (patch == ZYRE_VERSION_PATCH); // Create two nodes zyre_t *node1 = zyre_new ("node1"); assert (node1); assert (streq (zyre_name (node1), "node1")); zyre_set_header (node1, "X-HELLO", "World"); if (verbose) zyre_set_verbose (node1); // Set inproc endpoint for this node int rc = zyre_set_endpoint (node1, "inproc://zyre-node1"); assert (rc == 0); // Set up gossip network for this node zyre_gossip_bind (node1, "inproc://gossip-hub"); rc = zyre_start (node1); assert (rc == 0); zyre_t *node2 = zyre_new ("node2"); assert (node2); assert (streq (zyre_name (node2), "node2")); if (verbose) zyre_set_verbose (node2); // Set inproc endpoint for this node // First, try to use existing name, it'll fail rc = zyre_set_endpoint (node2, "inproc://zyre-node1"); assert (rc == -1); // Now use available name and confirm that it succeeds rc = zyre_set_endpoint (node2, "inproc://zyre-node2"); assert (rc == 0); // Set up gossip network for this node zyre_gossip_connect (node2, "inproc://gossip-hub"); rc = zyre_start (node2); assert (rc == 0); assert (strneq (zyre_uuid (node1), zyre_uuid (node2))); zyre_join (node1, "GLOBAL"); zyre_join (node2, "GLOBAL"); // Give time for them to interconnect zclock_sleep (250); if (verbose) zyre_dump (node1); zlist_t *peers = zyre_peers (node1); assert (peers); assert (zlist_size (peers) == 1); zlist_destroy (&peers); zyre_join (node1, "node1 group of one"); zyre_join (node2, "node2 group of one"); // Give them time to join their groups zclock_sleep (250); zlist_t *own_groups = zyre_own_groups (node1); assert (own_groups); assert (zlist_size (own_groups) == 2); zlist_destroy (&own_groups); zlist_t *peer_groups = zyre_peer_groups (node1); assert (peer_groups); assert (zlist_size (peer_groups) == 2); zlist_destroy (&peer_groups); char *value = zyre_peer_header_value (node2, zyre_uuid (node1), "X-HELLO"); assert (streq (value, "World")); zstr_free (&value); // One node shouts to GLOBAL zyre_shouts (node1, "GLOBAL", "Hello, World"); // Second node should receive ENTER, JOIN, and SHOUT zmsg_t *msg = zyre_recv (node2); assert (msg); char *command = zmsg_popstr (msg); assert (streq (command, "ENTER")); zstr_free (&command); assert (zmsg_size (msg) == 4); char *peerid = zmsg_popstr (msg); char *name = zmsg_popstr (msg); assert (streq (name, "node1")); zstr_free (&name); zframe_t *headers_packed = zmsg_pop (msg); char *address = zmsg_popstr (msg); char *endpoint = zyre_peer_address (node2, peerid); assert (streq (address, endpoint)); zstr_free (&peerid); zstr_free (&endpoint); zstr_free (&address); assert (headers_packed); zhash_t *headers = zhash_unpack (headers_packed); assert (headers); zframe_destroy (&headers_packed); assert (streq ((char *) zhash_lookup (headers, "X-HELLO"), "World")); zhash_destroy (&headers); zmsg_destroy (&msg); msg = zyre_recv (node2); assert (msg); command = zmsg_popstr (msg); assert (streq (command, "JOIN")); zstr_free (&command); assert (zmsg_size (msg) == 3); zmsg_destroy (&msg); msg = zyre_recv (node2); assert (msg); command = zmsg_popstr (msg); assert (streq (command, "JOIN")); zstr_free (&command); assert (zmsg_size (msg) == 3); zmsg_destroy (&msg); msg = zyre_recv (node2); assert (msg); command = zmsg_popstr (msg); assert (streq (command, "SHOUT")); zstr_free (&command); zmsg_destroy (&msg); zyre_stop (node2); msg = zyre_recv (node2); assert (msg); command = zmsg_popstr (msg); assert (streq (command, "STOP")); zstr_free (&command); zmsg_destroy (&msg); zyre_stop (node1); zyre_destroy (&node1); zyre_destroy (&node2); ----