README.md
1
2[![GitHub release](https://img.shields.io/github/release/zeromq/zyre.svg)](https://github.com/zeromq/zyre/releases)
3[![OBS draft](https://img.shields.io/badge/OBS%20master-draft-yellow.svg)](http://software.opensuse.org/download.html?project=network%3Amessaging%3Azeromq%3Agit-draft&package=zyre)
4[![OBS stable](https://img.shields.io/badge/OBS%20master-stable-yellow.svg)](http://software.opensuse.org/download.html?project=network%3Amessaging%3Azeromq%3Agit-stable&package=zyre)
5<a target="_blank" href="http://webchat.freenode.net?channels=%23zeromq&uio=d4"><img src="https://cloud.githubusercontent.com/assets/493242/14886493/5c660ea2-0d51-11e6-8249-502e6c71e9f2.png" height = "20" /></a>
6[![license](https://img.shields.io/badge/license-MPL%202.0-green.svg)](https://github.com/zeromq/zyre/blob/master/LICENSE)
7
8# Zyre - Local Area Clustering for Peer-to-Peer Applications
9
10| Linux & MacOSX | Windows |
11|:--------------:|:--------:|
12|[![Build Status](https://travis-ci.org/zeromq/zyre.png?branch=master)](https://travis-ci.org/zeromq/zyre)|[![Build status](https://ci.appveyor.com/api/projects/status/kuugogjji97yblqe?svg=true)](https://ci.appveyor.com/project/zeromq/zyre)|
13## Contents
14
15
16**[Overview](#overview)**
17
18**[Scope and Goals](#scope-and-goals)**
19
20**[Ownership and License](#ownership-and-license)**
21
22**[Using Zyre](#using-zyre)**
23
24**[Building on Linux and macOS](#building-on-linux-and-macos)**
25
26**[Building on Windows](#building-on-windows)**
27
28**[Building on Windows](#building-on-windows)**
29* [Using CMake](#using-cmake)
30
31**[Linking with an Application](#linking-with-an-application)**
32
33**[Use from Other Languages](#use-from-other-languages)**
34
35**[API Summary](#api-summary)**
36* [zyre - API wrapping one Zyre node](#zyre---api-wrapping-one-zyre-node)
37* [zyre_event - no title found](#zyre_event---no-title-found)
38
39**[Hints to Contributors](#hints-to-contributors)**
40
41**[This Document](#this-document)**
42
43## Overview
44
45### Scope and Goals
46
47Zyre provides reliable group messaging over local area networks. It has these key characteristics:
48
49* Zyre needs no administration or configuration.
50* Peers may join and leave the network at any time.
51* Peers talk to each other without any central brokers or servers.
52* Peers can talk directly to each other.
53* Peers can join groups, and then talk to groups.
54* Zyre is reliable, and loses no messages even when the network is heavily loaded.
55* Zyre is fast and has low latency, requiring no consensus protocols.
56* Zyre is designed for WiFi networks, yet also works well on Ethernet networks.
57* Time for a new peer to join a network is about one second.
58
59Typical use cases for Zyre are:
60
61* Local service discovery.
62* Clustering of a set of services on the same Ethernet network.
63* Controlling a network of smart devices (Internet of Things).
64* Multi-user mobile applications (like smart classrooms).
65
66Technical details:
67
68* Uses RFC 36 (http://rfc.zeromq.org/spec:36/ZRE) protocol for discovery and heartbeating.
69* Uses reliable Dealer-Router pattern for interconnection, assuring that messages are not lost unless a peer application terminates.
70* Optimized for WiFi, using UDP broadcasts for discovery and heartbeating…
71* Offers alternative discovery mechanism (gossip) for Ethernet networks.
72
73### Ownership and License
74
75The contributors are listed in AUTHORS. This project uses the MPL v2 license, see LICENSE.
76
77Zyre uses the [C4.1 (Collective Code Construction Contract)](http://rfc.zeromq.org/spec:22) process for contributions.
78
79Zyre uses the [CLASS (C Language Style for Scalabilty)](http://rfc.zeromq.org/spec:21) guide for code style.
80
81To report an issue, use the [Zyre issue tracker](https://github.com/zeromq/zyre/issues) at github.com.
82
83## Using Zyre
84
85### Building on Linux and macOS
86
87To start with, you need at least these packages:
88* `git` -- git is how we share code with other people.
89* `build-essential`, `libtool`, `pkg-config` - the C compiler and related tools.
90* `autotools-dev`, `autoconf`, `automake` - the GNU autoconf makefile generators.
91* `cmake` - the CMake makefile generators (an alternative to autoconf).
92
93Plus some others:
94* `uuid-dev`, `libpcre3-dev` - utility libraries.
95* `valgrind` - a useful tool for checking your code.
96* `pkg-config` - an optional useful tool to make building with dependencies easier.
97
98Which we install like this (using the Debian-style apt-get package manager):
99
100```
101 sudo apt-get update
102 sudo apt-get install -y \
103 git build-essential libtool \
104 pkg-config autotools-dev autoconf automake cmake \
105 uuid-dev libpcre3-dev valgrind
106
107 # only execute this next line if interested in updating the man pages as
108 # well (adds to build time):
109 sudo apt-get install -y asciidoc
110```
111Here's how to build Zyre from GitHub (building from packages is very similar, you don't clone a repo but unpack a tarball), including the libsodium (for security) and libzmq (ZeroMQ core) libraries:
112
113```
114 git clone --depth 1 -b stable https://github.com/jedisct1/libsodium.git
115 cd libsodium
116 ./autogen.sh && ./configure && make check
117 sudo make install
118 cd ..
119
120 git clone git://github.com/zeromq/libzmq.git
121 cd libzmq
122 ./autogen.sh
123 # do not specify "--with-libsodium" if you prefer to use internal tweetnacl
124 # security implementation (recommended for development)
125 ./configure --with-libsodium
126 make check
127 sudo make install
128 sudo ldconfig
129 cd ..
130
131 git clone git://github.com/zeromq/czmq.git
132 cd czmq
133 ./autogen.sh && ./configure && make check
134 sudo make install
135 sudo ldconfig
136 cd ..
137
138 git clone git://github.com/zeromq/zyre.git
139 cd zyre
140 ./autogen.sh && ./configure && make check
141 sudo make install
142 sudo ldconfig
143 cd ..
144```
145
146
147Test by running the `zyre_selftest` command:
148
149 zyre\src\.libs\zyre_selftest
150
151Test by running the `zpinger` command, from two or more PCs.
152
153 zyre\src\.libs\zpinger
154
155### Building on Windows
156
157To start with, you need MS Visual Studio (C/C++). The free community edition works well.
158
159Then, install git, and make sure it works from a DevStudio command prompt:
160
161```
162git
163```
164
165Now let's build Zyre from GitHub:
166
167```
168 git clone --depth 1 -b stable https://github.com/jedisct1/libsodium.git
169 git clone git://github.com/zeromq/libzmq.git
170 git clone git://github.com/zeromq/czmq.git
171 git clone git://github.com/zeromq/zyre.git
172 cd zyre\builds\msvc
173 configure.bat
174 cd build
175 buildall.bat
176 cd ..\..\..\..
177```
178
179Test by running the `zyre_selftest` command:
180```
181 dir/s/b zyre_selftest.exe
182 zyre\builds\msvc\vs2013\DebugDEXE\zyre_selftest.exe
183 zyre\builds\msvc\vs2013\ReleaseDEXE\zyre_selftest.exe
184
185 :: select your choice and run it
186 zyre\builds\msvc\vs2013\DebugDEXE\zyre_selftest.exe
187```
188Test by running `zpinger` from two or more PCs:
189
190```
191 dir/s/b zpinger.exe
192 zyre\builds\msvc\vs2013\DebugDEXE\zpinger.exe
193 zyre\builds\msvc\vs2013\ReleaseDEXE\zpinger.exe
194 zyre\builds\msvc\vs2013\x64\DebugDEXE\zpinger.exe
195
196 :: select your choice and run it
197 zyre\builds\msvc\vs2013\ReleaseDEXE\zpinger.exe
198```
199
200### Building on Windows
201
202To start with, you need MS Visual Studio (C/C++). The free community edition works well.
203
204Then, install git, and make sure it works from a DevStudio command prompt:
205
206```
207git
208```
209
210#### Using CMake
211
212`zyre` requires `czmq` and `libzmq`, so we need to build `libzmq` first. For `libzmq`, you can optionally use [libsodium](https://github.com/jedisct1/libsodium) as the curve encryption library. So we will start from building `libsodium` in the following (and you can bypass the building of `libsodium` if you are ok with libzmq's default curve encryption library):
213
214```
215git clone --depth 1 -b stable https://github.com/jedisct1/libsodium.git
216cd libsodium\builds\msvc\build
217buildall.bat
218cd ..\..\..\..
219```
220
221Once done, you can find the library files under `libsodium\bin\<Win32|x64>\<Debug|Release>\<Platform Toolset>\<dynamic|ltcg|static>`.
222
223Here, the `<Platform Toolset>` is the platform toolset you are using: `v100` for `VS2010`, `v140` for `VS2015`, `v141` for `VS2017`, etc.
224
225```
226git clone git://github.com/zeromq/libzmq.git
227cd libzmq
228mkdir build
229cd build
230cmake .. -DBUILD_STATIC=OFF -DBUILD_SHARED=ON -DZMQ_BUILD_TESTS=ON -DWITH_LIBSODIUM=ON -DCMAKE_INCLUDE_PATH=..\libsodium\src\libsodium\include -DCMAKE_LIBRARY_PATH=..\libsodium\bin\Win32\Release\<Platform Toolset>\dynamic -DCMAKE_INSTALL_PREFIX=C:\projects\libs
231cmake --build . --config Release --target install
232cd ..\..\
233```
234`-DWITH_LIBSODIUM=ON` is necessary if you want to build `libzmq` with `libsodium`. `CMAKE_INCLUDE_PATH` option tells `libzmq` where to search for `libsodium`'s header files. And the `CMAKE_LIBRARY_PATH` option tells where to search for libsodium library files. If you don't need `libsodium` support, you can omit these three options.
235
236`-DCMAKE_INSTALL_PREFIX=C:\libzmq` means we want to install `libzmq` into the `C:\libzmq`. You may need to run your shell with administrator privilege in order to write to the system disk.
237
238Next, let's build `czmq`:
239
240```
241git clone git://github.com/zeromq/czmq.git
242cd czmq
243mkdir build
244cd build
245cmake .. -DCZMQ_BUILD_SHARED=ON -DCZMQ_BUILD_STATIC=OFF -DCMAKE_PREFIX_PATH=C:\projects\libs -DCMAKE_INSTALL_PREFIX=C:\projects\libs
246cmake --build . --config Release --target install
247```
248
249Remember that we installed `libzmq` to `C:\projects\libs` through specifying `-DCMAKE_INSTALL_PREFIX` in the previous step. We here use `-DCMAKE_PREFIX_PATH=C:\projects\libs` to tell `czmq` where to search for `libzmq`.
250
251That is not the whole story. We didn't mention the building of `libcurl`, `lz4`, `libuuid` and other `czmq` optional libraries above. In fact, to build all of these optional libraries successfully is really tricky. Please refer issue [#1972](https://github.com/zeromq/czmq/issues/1972) for more details.
252
253Now, it is time to build `zyre`:
254
255```
256git clone git://github.com/zeromq/zyre.git
257cd zyre
258mkdir build
259cd build
260cmake .. -DZYRE_BUILD_SHARED=ON -DZYRE_BUILD_STATIC=OFF -DCMAKE_PREFIX_PATH=C:\projects\libs
261cmake --build . --config Release
262ctest -C Release
263```
264
265### Linking with an Application
266
267Include `zyre.h` in your application and link with libzyre. Here is a typical gcc link command:
268
269 gcc myapp.c -lzyre -lczmq -lzmq -o myapp
270
271### Use from Other Languages
272
273This is a list of auto-generated bindings:
274
275* https://github.com/zeromq/zyre/tree/master/bindings/jni - Java ([Examples](https://github.com/zeromq/zyre/tree/master/examples/jni))
276* https://github.com/zeromq/zyre/tree/master/bindings/nodejs - NodeJS
277* https://github.com/zeromq/zyre/tree/master/bindings/python - Python
278* https://github.com/zeromq/zyre/tree/master/bindings/python_cffi - Python (cffi)
279* https://github.com/zeromq/zyre/tree/master/bindings/qml - QML
280* https://github.com/zeromq/zyre/tree/master/bindings/qt - Qt
281* https://github.com/zeromq/zyre/tree/master/bindings/ruby - Ruby (FFI)
282
283### API Summary
284
285This is the API provided by Zyre 2.x, in alphabetical order.
286
287#### zyre - API wrapping one Zyre node
288
289Zyre does local area discovery and clustering. A Zyre node broadcasts
290UDP beacons, and connects to peers that it finds. This class wraps a
291Zyre node with a message-based API.
292
293All incoming events are zmsg_t messages delivered via the zyre_recv
294call. The first frame defines the type of the message, and following
295frames provide further values:
296
297 ENTER fromnode name headers ipaddress:port
298 a new peer has entered the network
299 EVASIVE fromnode name
300 a peer is being evasive (i.e. quiet) and will be pinged manually
301 SILENT fromnode name
302 a peer has been quiet and has not answered ping after 1 second
303 EXIT fromnode name
304 a peer has left the network
305 JOIN fromnode name groupname
306 a peer has joined a specific group
307 LEAVE fromnode name groupname
308 a peer has joined a specific group
309 WHISPER fromnode name message
310 a peer has sent this node a message
311 SHOUT fromnode name groupname message
312 a peer has sent one of our groups a message
313
314In SHOUT and WHISPER the message is zero or more frames, and can hold
315any ZeroMQ message. In ENTER, the headers frame contains a packed
316dictionary, see zhash_pack/unpack.
317
318To join or leave a group, use the zyre_join and zyre_leave methods.
319To set a header value, use the zyre_set_header method. To send a message
320to a single peer, use zyre_whisper. To send a message to a group, use
321zyre_shout.
322
323Todo: allow multipart contents
324
325This is the class interface:
326
327```h
328 // This is a stable class, and may not change except for emergencies. It
329 // is provided in stable builds.
330 // This class has draft methods, which may change over time. They are not
331 // in stable releases, by default. Use --enable-drafts to enable.
332 // Constructor, creates a new Zyre node. Note that until you start the
333 // node it is silent and invisible to other nodes on the network.
334 // The node name is provided to other nodes during discovery. If you
335 // specify NULL, Zyre generates a randomized node name from the UUID.
336 ZYRE_EXPORT zyre_t *
337 zyre_new (const char *name);
338
339 // Destructor, destroys a Zyre node. When you destroy a node, any
340 // messages it is sending or receiving will be discarded.
341 ZYRE_EXPORT void
342 zyre_destroy (zyre_t **self_p);
343
344 // Return our node UUID string, after successful initialization
345 ZYRE_EXPORT const char *
346 zyre_uuid (zyre_t *self);
347
348 // Return our node name, after successful initialization. First 6
349 // characters of UUID by default.
350 ZYRE_EXPORT const char *
351 zyre_name (zyre_t *self);
352
353 // Set the public name of this node overriding the default. The name is
354 // provide during discovery and come in each ENTER message.
355 ZYRE_EXPORT void
356 zyre_set_name (zyre_t *self, const char *name);
357
358 // Set node header; these are provided to other nodes during discovery
359 // and come in each ENTER message.
360 ZYRE_EXPORT void
361 zyre_set_header (zyre_t *self, const char *name, const char *format, ...) CHECK_PRINTF (3);
362
363 // Set verbose mode; this tells the node to log all traffic as well as
364 // all major events.
365 ZYRE_EXPORT void
366 zyre_set_verbose (zyre_t *self);
367
368 // Set UDP beacon discovery port; defaults to 5670, this call overrides
369 // that so you can create independent clusters on the same network, for
370 // e.g. development vs. production. Has no effect after zyre_start().
371 ZYRE_EXPORT void
372 zyre_set_port (zyre_t *self, int port_nbr);
373
374 // Set the peer evasiveness timeout, in milliseconds. Default is 5000.
375 // This can be tuned in order to deal with expected network conditions
376 // and the response time expected by the application. This is tied to
377 // the beacon interval and rate of messages received.
378 ZYRE_EXPORT void
379 zyre_set_evasive_timeout (zyre_t *self, int interval);
380
381 // Set the peer silence timeout, in milliseconds. Default is 5000.
382 // This can be tuned in order to deal with expected network conditions
383 // and the response time expected by the application. This is tied to
384 // the beacon interval and rate of messages received.
385 // Silence is triggered one second after the timeout if peer has not
386 // answered ping and has not sent any message.
387 // NB: this is currently redundant with the evasiveness timeout. Both
388 // affect the same timeout value.
389 ZYRE_EXPORT void
390 zyre_set_silent_timeout (zyre_t *self, int interval);
391
392 // Set the peer expiration timeout, in milliseconds. Default is 30000.
393 // This can be tuned in order to deal with expected network conditions
394 // and the response time expected by the application. This is tied to
395 // the beacon interval and rate of messages received.
396 ZYRE_EXPORT void
397 zyre_set_expired_timeout (zyre_t *self, int interval);
398
399 // Set UDP beacon discovery interval, in milliseconds. Default is instant
400 // beacon exploration followed by pinging every 1,000 msecs.
401 ZYRE_EXPORT void
402 zyre_set_interval (zyre_t *self, size_t interval);
403
404 // Set network interface for UDP beacons. If you do not set this, CZMQ will
405 // choose an interface for you. On boxes with several interfaces you should
406 // specify which one you want to use, or strange things can happen.
407 ZYRE_EXPORT void
408 zyre_set_interface (zyre_t *self, const char *value);
409
410 // By default, Zyre binds to an ephemeral TCP port and broadcasts the local
411 // host name using UDP beaconing. When you call this method, Zyre will use
412 // gossip discovery instead of UDP beaconing. You MUST set-up the gossip
413 // service separately using zyre_gossip_bind() and _connect(). Note that the
414 // endpoint MUST be valid for both bind and connect operations. You can use
415 // inproc://, ipc://, or tcp:// transports (for tcp://, use an IP address
416 // that is meaningful to remote as well as local nodes). Returns 0 if
417 // the bind was successful, else -1.
418 ZYRE_EXPORT int
419 zyre_set_endpoint (zyre_t *self, const char *format, ...) CHECK_PRINTF (2);
420
421 // Set-up gossip discovery of other nodes. At least one node in the cluster
422 // must bind to a well-known gossip endpoint, so other nodes can connect to
423 // it. Note that gossip endpoints are completely distinct from Zyre node
424 // endpoints, and should not overlap (they can use the same transport).
425 ZYRE_EXPORT void
426 zyre_gossip_bind (zyre_t *self, const char *format, ...) CHECK_PRINTF (2);
427
428 // Set-up gossip discovery of other nodes. A node may connect to multiple
429 // other nodes, for redundancy paths. For details of the gossip network
430 // design, see the CZMQ zgossip class.
431 ZYRE_EXPORT void
432 zyre_gossip_connect (zyre_t *self, const char *format, ...) CHECK_PRINTF (2);
433
434 // Start node, after setting header values. When you start a node it
435 // begins discovery and connection. Returns 0 if OK, -1 if it wasn't
436 // possible to start the node.
437 ZYRE_EXPORT int
438 zyre_start (zyre_t *self);
439
440 // Stop node; this signals to other peers that this node will go away.
441 // This is polite; however you can also just destroy the node without
442 // stopping it.
443 ZYRE_EXPORT void
444 zyre_stop (zyre_t *self);
445
446 // Join a named group; after joining a group you can send messages to
447 // the group and all Zyre nodes in that group will receive them.
448 ZYRE_EXPORT int
449 zyre_join (zyre_t *self, const char *group);
450
451 // Leave a group
452 ZYRE_EXPORT int
453 zyre_leave (zyre_t *self, const char *group);
454
455 // Receive next message from network; the message may be a control
456 // message (ENTER, EXIT, JOIN, LEAVE) or data (WHISPER, SHOUT).
457 // Returns zmsg_t object, or NULL if interrupted
458 // Caller owns return value and must destroy it when done.
459 ZYRE_EXPORT zmsg_t *
460 zyre_recv (zyre_t *self);
461
462 // Send message to single peer, specified as a UUID string
463 // Destroys message after sending
464 ZYRE_EXPORT int
465 zyre_whisper (zyre_t *self, const char *peer, zmsg_t **msg_p);
466
467 // Send message to a named group
468 // Destroys message after sending
469 ZYRE_EXPORT int
470 zyre_shout (zyre_t *self, const char *group, zmsg_t **msg_p);
471
472 // Send formatted string to a single peer specified as UUID string
473 ZYRE_EXPORT int
474 zyre_whispers (zyre_t *self, const char *peer, const char *format, ...) CHECK_PRINTF (3);
475
476 // Send formatted string to a named group
477 ZYRE_EXPORT int
478 zyre_shouts (zyre_t *self, const char *group, const char *format, ...) CHECK_PRINTF (3);
479
480 // Return zlist of current peer ids.
481 // Caller owns return value and must destroy it when done.
482 ZYRE_EXPORT zlist_t *
483 zyre_peers (zyre_t *self);
484
485 // Return zlist of current peers of this group.
486 // Caller owns return value and must destroy it when done.
487 ZYRE_EXPORT zlist_t *
488 zyre_peers_by_group (zyre_t *self, const char *name);
489
490 // Return zlist of currently joined groups.
491 // Caller owns return value and must destroy it when done.
492 ZYRE_EXPORT zlist_t *
493 zyre_own_groups (zyre_t *self);
494
495 // Return zlist of groups known through connected peers.
496 // Caller owns return value and must destroy it when done.
497 ZYRE_EXPORT zlist_t *
498 zyre_peer_groups (zyre_t *self);
499
500 // Return the endpoint of a connected peer.
501 // Returns empty string if peer does not exist.
502 // Caller owns return value and must destroy it when done.
503 ZYRE_EXPORT char *
504 zyre_peer_address (zyre_t *self, const char *peer);
505
506 // Return the value of a header of a conected peer.
507 // Returns null if peer or key doesn't exits.
508 // Caller owns return value and must destroy it when done.
509 ZYRE_EXPORT char *
510 zyre_peer_header_value (zyre_t *self, const char *peer, const char *name);
511
512 // Return socket for talking to the Zyre node, for polling
513 ZYRE_EXPORT zsock_t *
514 zyre_socket (zyre_t *self);
515
516 // Print zyre node information to stdout
517 ZYRE_EXPORT void
518 zyre_print (zyre_t *self);
519
520 // Return the Zyre version for run-time API detection; returns
521 // major * 10000 + minor * 100 + patch, as a single integer.
522 ZYRE_EXPORT uint64_t
523 zyre_version (void);
524
525 // Self test of this class.
526 ZYRE_EXPORT void
527 zyre_test (bool verbose);
528
529 #ifdef ZYRE_BUILD_DRAFT_API
530 // *** Draft method, for development use, may change without warning ***
531 // Set the TCP port bound by the ROUTER peer-to-peer socket (beacon mode).
532 // Defaults to * (the port is randomly assigned by the system).
533 // This call overrides this, to bypass some firewall issues when ports are
534 // random. Has no effect after zyre_start().
535 ZYRE_EXPORT void
536 zyre_set_beacon_peer_port (zyre_t *self, int port_nbr);
537
538 // *** Draft method, for development use, may change without warning ***
539 // This options enables a peer to actively contest for leadership in the
540 // given group. If this option is not set the peer will still participate in
541 // elections but never gets elected. This ensures that a consent for a leader
542 // is reached within a group even though not every peer is contesting for
543 // leadership.
544 ZYRE_EXPORT void
545 zyre_set_contest_in_group (zyre_t *self, const char *group);
546
547 // *** Draft method, for development use, may change without warning ***
548 // Set an alternative endpoint value when using GOSSIP ONLY. This is useful
549 // if you're advertising an endpoint behind a NAT.
550 ZYRE_EXPORT void
551 zyre_set_advertised_endpoint (zyre_t *self, const char *value);
552
553 // *** Draft method, for development use, may change without warning ***
554 // Apply a azcert to a Zyre node.
555 ZYRE_EXPORT void
556 zyre_set_zcert (zyre_t *self, zcert_t *zcert);
557
558 // *** Draft method, for development use, may change without warning ***
559 // Specify the ZAP domain (for use with CURVE).
560 ZYRE_EXPORT void
561 zyre_set_zap_domain (zyre_t *self, const char *domain);
562
563 // *** Draft method, for development use, may change without warning ***
564 // Set-up gossip discovery with CURVE enabled.
565 ZYRE_EXPORT void
566 zyre_gossip_connect_curve (zyre_t *self, const char *public_key, const char *format, ...) CHECK_PRINTF (3);
567
568 // *** Draft method, for development use, may change without warning ***
569 // Unpublish a GOSSIP node from local list, useful in removing nodes from list when they EXIT
570 ZYRE_EXPORT void
571 zyre_gossip_unpublish (zyre_t *self, const char *node);
572
573 // *** Draft method, for development use, may change without warning ***
574 // Explicitly connect to a peer
575 ZYRE_EXPORT int
576 zyre_require_peer (zyre_t *self, const char *uuid, const char *endpoint, const char *public_key);
577
578 #endif // ZYRE_BUILD_DRAFT_API
579```
580Please add '@interface' section in './../src/zyre.c'.
581
582This is the class self test code:
583
584```c
585 // We'll use inproc gossip discovery so that this works without networking
586
587 uint64_t version = zyre_version ();
588 assert ((version / 10000) % 100 == ZYRE_VERSION_MAJOR);
589 assert ((version / 100) % 100 == ZYRE_VERSION_MINOR);
590 assert (version % 100 == ZYRE_VERSION_PATCH);
591
592 // Create two nodes
593 zyre_t *node1 = zyre_new ("node1");
594 assert (node1);
595 assert (streq (zyre_name (node1), "node1"));
596 zyre_set_header (node1, "X-HELLO", "World");
597 if (verbose)
598 zyre_set_verbose (node1);
599
600 // Set inproc endpoint for this node
601 int rc = zyre_set_endpoint (node1, "inproc://zyre-node1");
602 assert (rc == 0);
603 // Set up gossip network for this node
604 zyre_gossip_bind (node1, "inproc://gossip-hub");
605 rc = zyre_start (node1);
606 assert (rc == 0);
607
608 zyre_t *node2 = zyre_new ("node2");
609 assert (node2);
610 assert (streq (zyre_name (node2), "node2"));
611 if (verbose)
612 zyre_set_verbose (node2);
613
614 // Set inproc endpoint for this node
615 // First, try to use existing name, it'll fail
616 rc = zyre_set_endpoint (node2, "inproc://zyre-node1");
617 assert (rc == -1);
618 // Now use available name and confirm that it succeeds
619 rc = zyre_set_endpoint (node2, "inproc://zyre-node2");
620 assert (rc == 0);
621
622 // Set up gossip network for this node
623 zyre_gossip_connect (node2, "inproc://gossip-hub");
624 rc = zyre_start (node2);
625 assert (rc == 0);
626 assert (strneq (zyre_uuid (node1), zyre_uuid (node2)));
627
628 zyre_join (node1, "GLOBAL");
629 zyre_join (node2, "GLOBAL");
630
631 // Give time for them to interconnect
632 zclock_sleep (250);
633 if (verbose)
634 zyre_dump (node1);
635
636 zlist_t *peers = zyre_peers (node1);
637 assert (peers);
638 assert (zlist_size (peers) == 1);
639 zlist_destroy (&peers);
640
641 zyre_join (node1, "node1 group of one");
642 zyre_join (node2, "node2 group of one");
643
644 // Give them time to join their groups
645 zclock_sleep (250);
646
647 zlist_t *own_groups = zyre_own_groups (node1);
648 assert (own_groups);
649 assert (zlist_size (own_groups) == 2);
650 zlist_destroy (&own_groups);
651
652 zlist_t *peer_groups = zyre_peer_groups (node1);
653 assert (peer_groups);
654 assert (zlist_size (peer_groups) == 2);
655 zlist_destroy (&peer_groups);
656
657 char *value = zyre_peer_header_value (node2, zyre_uuid (node1), "X-HELLO");
658 assert (streq (value, "World"));
659 zstr_free (&value);
660
661 // One node shouts to GLOBAL
662 zyre_shouts (node1, "GLOBAL", "Hello, World");
663
664 // Second node should receive ENTER, JOIN, and SHOUT
665 zmsg_t *msg = zyre_recv (node2);
666 assert (msg);
667 char *command = zmsg_popstr (msg);
668 assert (streq (command, "ENTER"));
669 zstr_free (&command);
670 assert (zmsg_size (msg) == 4);
671 char *peerid = zmsg_popstr (msg);
672 char *name = zmsg_popstr (msg);
673 assert (streq (name, "node1"));
674 zstr_free (&name);
675 zframe_t *headers_packed = zmsg_pop (msg);
676
677 char *address = zmsg_popstr (msg);
678 char *endpoint = zyre_peer_address (node2, peerid);
679 assert (streq (address, endpoint));
680 zstr_free (&peerid);
681 zstr_free (&endpoint);
682 zstr_free (&address);
683
684 assert (headers_packed);
685 zhash_t *headers = zhash_unpack (headers_packed);
686 assert (headers);
687 zframe_destroy (&headers_packed);
688 assert (streq ((char *) zhash_lookup (headers, "X-HELLO"), "World"));
689 zhash_destroy (&headers);
690 zmsg_destroy (&msg);
691
692 msg = zyre_recv (node2);
693 assert (msg);
694 command = zmsg_popstr (msg);
695 assert (streq (command, "JOIN"));
696 zstr_free (&command);
697 assert (zmsg_size (msg) == 3);
698 zmsg_destroy (&msg);
699
700 msg = zyre_recv (node2);
701 assert (msg);
702 command = zmsg_popstr (msg);
703 assert (streq (command, "JOIN"));
704 zstr_free (&command);
705 assert (zmsg_size (msg) == 3);
706 zmsg_destroy (&msg);
707
708 msg = zyre_recv (node2);
709 assert (msg);
710 command = zmsg_popstr (msg);
711 assert (streq (command, "SHOUT"));
712 zstr_free (&command);
713 zmsg_destroy (&msg);
714
715 zyre_stop (node2);
716
717 msg = zyre_recv (node2);
718 assert (msg);
719 command = zmsg_popstr (msg);
720 assert (streq (command, "STOP"));
721 zstr_free (&command);
722 zmsg_destroy (&msg);
723
724 zyre_stop (node1);
725
726 zyre_destroy (&node1);
727 zyre_destroy (&node2);
728
729 printf ("OK\n");
730
731 #ifdef ZYRE_BUILD_DRAFT_API
732 // DRAFT-API: Security
733 if (zsys_has_curve()){
734
735 printf (" * zyre-curve: ");
736 if (verbose)
737 printf ("\n");
738
739 if (verbose)
740 zsys_debug("----------------TESTING CURVE --------------");
741
742 zactor_t *speaker = zactor_new (zbeacon, NULL);
743 assert (speaker);
744 if (verbose)
745 zstr_sendx (speaker, "VERBOSE", NULL);
746
747 // ensuring we have a broadcast address
748 zsock_send (speaker, "si", "CONFIGURE", 9999);
749 char *hostname = zstr_recv (speaker);
750 if (!*hostname) {
751 printf ("OK (skipping test, no UDP broadcasting)\n");
752 zactor_destroy (&speaker);
753 freen (hostname);
754 return;
755 }
756 freen (hostname);
757 zactor_destroy (&speaker);
758
759
760 // zap setup
761 zactor_t *auth = zactor_new(zauth, NULL);
762 assert (auth);
763
764 if (verbose) {
765 zstr_sendx(auth, "VERBOSE", NULL);
766 zsock_wait(auth);
767 }
768
769 zstr_sendx (auth, "CURVE", CURVE_ALLOW_ANY, NULL);
770 zsock_wait (auth);
771
772 zyre_t *node3 = zyre_new ("node3");
773 zyre_t *node4 = zyre_new ("node4");
774
775 assert (node3);
776 assert (node4);
777
778 if (verbose) {
779 zyre_set_verbose (node3);
780 zyre_set_verbose (node4);
781 }
782
783 zyre_set_zap_domain(node3, "TEST");
784 zyre_set_zap_domain(node4, "TEST");
785
786 zsock_set_rcvtimeo(node3->inbox, 10000);
787 zsock_set_rcvtimeo(node4->inbox, 10000);
788
789 zcert_t *node3_cert = zcert_new ();
790 zcert_t *node4_cert = zcert_new ();
791
792 assert (node3_cert);
793 assert (node4_cert);
794
795 zyre_set_zcert (node3, node3_cert);
796 zyre_set_zcert (node4, node4_cert);
797
798 zyre_set_header (node3, "X-PUBLICKEY", "%s", zcert_public_txt (node3_cert));
799 zyre_set_header (node4, "X-PUBLICKEY", "%s", zcert_public_txt (node4_cert));
800
801 // test beacon
802 if (verbose)
803 zsys_debug ("----------------TESTING BEACON----------------");
804
805 rc = zyre_start (node3);
806 assert (rc == 0);
807
808 rc = zyre_start (node4);
809 assert (rc == 0);
810
811 zyre_join (node3, "GLOBAL");
812 zyre_join (node4, "GLOBAL");
813
814 zclock_sleep (1500);
815
816 if (verbose) {
817 zyre_dump (node3);
818 zyre_dump (node4);
819 }
820
821 zyre_shouts (node3, "GLOBAL", "Hello, World");
822
823 // Second node should receive ENTER, JOIN, and SHOUT
824 msg = zyre_recv (node4);
825 assert (msg);
826 command = zmsg_popstr (msg);
827 assert (streq (command, "ENTER"));
828 zstr_free (&command);
829
830 char *peerid = zmsg_popstr (msg);
831 assert (peerid);
832 name = zmsg_popstr (msg);
833 assert (streq (name, "node3"));
834 zmsg_destroy (&msg);
835
836 msg = zyre_recv (node4);
837 assert (msg);
838 command = zmsg_popstr (msg);
839 assert (streq (command, "JOIN"));
840 zstr_free (&command);
841 zmsg_destroy (&msg);
842
843 msg = zyre_recv (node4);
844 assert (msg);
845 command = zmsg_popstr (msg);
846 assert (streq (command, "SHOUT"));
847 zstr_free (&command);
848 zmsg_destroy (&msg);
849
850 zyre_leave (node3, "GLOBAL");
851 zyre_leave (node4, "GLOBAL");
852
853 zstr_free (&name);
854 zstr_free (&peerid);
855 zstr_free (&command);
856
857 zyre_stop (node3);
858 zyre_stop (node4);
859
860 // give things a chance to settle...
861 zclock_sleep (250);
862
863 zyre_destroy(&node3);
864 zyre_destroy(&node4);
865
866 zcert_destroy(&node3_cert);
867 zcert_destroy(&node4_cert);
868
869 // test gossip
870 if (verbose)
871 zsys_debug ("----------------TESTING GOSSIP----------------");
872
873 zyre_t *node5 = zyre_new ("node5");
874 zyre_t *node6 = zyre_new ("node6");
875
876 assert (node5);
877 assert (node6);
878
879 if (verbose) {
880 zyre_set_verbose (node5);
881 zyre_set_verbose (node6);
882 }
883
884 // if it takes more than 10s, something probably went terribly wrong
885 zsock_set_rcvtimeo(node5->inbox, 10000);
886 zsock_set_rcvtimeo(node6->inbox, 10000);
887
888 zcert_t *node5_cert = zcert_new ();
889 zcert_t *node6_cert = zcert_new ();
890
891 assert (node5_cert);
892 assert (node6_cert);
893
894 zyre_set_zcert(node5, node5_cert);
895 zyre_set_zcert(node6, node6_cert);
896
897 zyre_set_header(node5, "X-PUBLICKEY", "%s", zcert_public_txt(node5_cert));
898 zyre_set_header(node6, "X-PUBLICKEY", "%s", zcert_public_txt(node6_cert));
899
900 // TODO- set_advertised_endpoint tests
901 // zyre_set_endpoint(node5, "tcp://127.0.0.1:9001");
902 // zyre_set_advertised_endpoint(node5, "tcp://localhost:9001");
903
904 const char *gossip_cert = zcert_public_txt (node5_cert);
905
906 // TODO- need to add zyre_gossip_port functions to get port from gossip bind(?)
907 zyre_gossip_bind(node5, "tcp://127.0.0.1:9001");
908 zyre_gossip_connect_curve(node6, gossip_cert, "tcp://127.0.0.1:9001");
909
910 rc = zyre_start (node5);
911 assert (rc == 0);
912
913 rc = zyre_start (node6);
914 assert (rc == 0);
915
916 zyre_join (node5, "GLOBAL");
917 zyre_join (node6, "GLOBAL");
918
919 // give things a chance to settle...
920 zclock_sleep (1500);
921
922 if (verbose) {
923 zyre_dump (node5);
924 zyre_dump (node6);
925 }
926
927 zyre_shouts (node5, "GLOBAL", "Hello, World");
928
929 // Second node should receive ENTER, JOIN, and SHOUT
930 msg = zyre_recv (node6);
931 assert (msg);
932 command = zmsg_popstr (msg);
933 assert (streq (command, "ENTER"));
934 zstr_free (&command);
935
936 peerid = zmsg_popstr (msg);
937 assert (peerid);
938 name = zmsg_popstr (msg);
939 zmsg_destroy (&msg);
940
941 assert (streq (name, "node5"));
942 zstr_free (&name);
943
944 zyre_leave (node5, "GLOBAL");
945 zyre_leave (node6, "GLOBAL");
946
947 zyre_stop (node5);
948 zyre_stop (node6);
949
950 // give things a chance to settle...
951 zclock_sleep (250);
952
953 zstr_free (&peerid);
954
955 zcert_destroy (&node5_cert);
956 zcert_destroy (&node6_cert);
957
958 zyre_destroy (&node5);
959 zyre_destroy (&node6);
960 zactor_destroy (&auth);
961
962 printf ("OK\n");
963
964 }
965 #endif
966 }
967```
968
969#### zyre_event - no title found
970
971This class provides a higher-level API to the zyre_recv call, by doing
972work that you will want to do in many cases, such as unpacking the peer
973headers for each ENTER event received.
974
975Please add '@discuss' section in './../src/zyre_event.c'.
976
977This is the class interface:
978
979```h
980 // This is a stable class, and may not change except for emergencies. It
981 // is provided in stable builds.
982 // Constructor: receive an event from the zyre node, wraps zyre_recv.
983 // The event may be a control message (ENTER, EXIT, JOIN, LEAVE) or
984 // data (WHISPER, SHOUT).
985 ZYRE_EXPORT zyre_event_t *
986 zyre_event_new (zyre_t *node);
987
988 // Destructor; destroys an event instance
989 ZYRE_EXPORT void
990 zyre_event_destroy (zyre_event_t **self_p);
991
992 // Returns event type, as printable uppercase string. Choices are:
993 // "ENTER", "EXIT", "JOIN", "LEAVE", "EVASIVE", "WHISPER" and "SHOUT"
994 // and for the local node: "STOP"
995 ZYRE_EXPORT const char *
996 zyre_event_type (zyre_event_t *self);
997
998 // Return the sending peer's uuid as a string
999 ZYRE_EXPORT const char *
1000 zyre_event_peer_uuid (zyre_event_t *self);
1001
1002 // Return the sending peer's public name as a string
1003 ZYRE_EXPORT const char *
1004 zyre_event_peer_name (zyre_event_t *self);
1005
1006 // Return the sending peer's ipaddress as a string
1007 ZYRE_EXPORT const char *
1008 zyre_event_peer_addr (zyre_event_t *self);
1009
1010 // Returns the event headers, or NULL if there are none
1011 ZYRE_EXPORT zhash_t *
1012 zyre_event_headers (zyre_event_t *self);
1013
1014 // Returns value of a header from the message headers
1015 // obtained by ENTER. Return NULL if no value was found.
1016 ZYRE_EXPORT const char *
1017 zyre_event_header (zyre_event_t *self, const char *name);
1018
1019 // Returns the group name that a SHOUT event was sent to
1020 ZYRE_EXPORT const char *
1021 zyre_event_group (zyre_event_t *self);
1022
1023 // Returns the incoming message payload; the caller can modify the
1024 // message but does not own it and should not destroy it.
1025 ZYRE_EXPORT zmsg_t *
1026 zyre_event_msg (zyre_event_t *self);
1027
1028 // Returns the incoming message payload, and pass ownership to the
1029 // caller. The caller must destroy the message when finished with it.
1030 // After called on the given event, further calls will return NULL.
1031 // Caller owns return value and must destroy it when done.
1032 ZYRE_EXPORT zmsg_t *
1033 zyre_event_get_msg (zyre_event_t *self);
1034
1035 // Print event to zsys log
1036 ZYRE_EXPORT void
1037 zyre_event_print (zyre_event_t *self);
1038
1039 // Self test of this class.
1040 ZYRE_EXPORT void
1041 zyre_event_test (bool verbose);
1042
1043```
1044Please add '@interface' section in './../src/zyre_event.c'.
1045
1046This is the class self test code:
1047
1048```c
1049 // Create two nodes
1050 zyre_t *node1 = zyre_new ("node1");
1051 assert (node1);
1052 zyre_set_header (node1, "X-HELLO", "World");
1053 int rc = zyre_set_endpoint (node1, "inproc://zyre-node1");
1054 assert (rc == 0);
1055 // use gossiping instead of beaconing, suits Travis better
1056 zyre_gossip_bind (node1, "inproc://gossip-hub");
1057 if (verbose)
1058 zyre_set_verbose (node1);
1059 if (zyre_start (node1)) {
1060 zyre_destroy (&node1);
1061 printf ("OK (skipping test, no UDP discovery)\n");
1062 return;
1063 }
1064 zyre_join (node1, "GLOBAL");
1065
1066 zyre_t *node2 = zyre_new ("node2");
1067 assert (node2);
1068 if (verbose)
1069 zyre_set_verbose (node2);
1070 rc = zyre_set_endpoint (node2, "inproc://zyre-node2");
1071 assert (rc == 0);
1072 // use gossiping instead of beaconing, suits Travis better
1073 zyre_gossip_connect (node2, "inproc://gossip-hub");
1074 rc = zyre_start (node2);
1075 assert (rc == 0);
1076 zyre_join (node2, "GLOBAL");
1077
1078 // Give time for them to interconnect
1079 zclock_sleep (250);
1080
1081 // One node shouts to GLOBAL
1082 zmsg_t *msg = zmsg_new ();
1083 zmsg_addstr (msg, "Hello, World");
1084 zyre_shout (node1, "GLOBAL", &msg);
1085 zclock_sleep (100);
1086
1087 // Parse ENTER
1088 zyre_event_t *event = zyre_event_new (node2);
1089 assert (streq (zyre_event_type (event), "ENTER"));
1090 const char *sender = zyre_event_peer_uuid (event);
1091 assert (sender);
1092 const char *name = zyre_event_peer_name (event);
1093 assert (name);
1094 assert (streq (name, "node1"));
1095 const char *address = zyre_event_peer_addr (event);
1096 assert (address);
1097 const char *header = zyre_event_header (event, "X-HELLO");
1098 assert (header);
1099 zyre_event_destroy (&event);
1100
1101 // Parse JOIN
1102 // We tolerate other events, which we can get if there are instances
1103 // of Zyre running somewhere on the network.
1104 event = zyre_event_new (node2);
1105 if (streq (zyre_event_type (event), "JOIN")) {
1106 // Parse SHOUT
1107 zyre_event_destroy (&event);
1108 event = zyre_event_new (node2);
1109 if (streq (zyre_event_type (event), "SHOUT")) {
1110 assert (streq (zyre_event_group (event), "GLOBAL"));
1111 zmsg_t *msg = zyre_event_get_msg (event);
1112 char *string = zmsg_popstr (msg);
1113 zmsg_destroy (&msg);
1114 assert (streq (string, "Hello, World"));
1115 free (string);
1116 }
1117 zyre_event_destroy (&event);
1118 }
1119 zyre_destroy (&node1);
1120 zyre_destroy (&node2);
1121```
1122
1123
1124### Hints to Contributors
1125
1126Zyre is a nice, neat library, and you may not immediately appreciate why. Read the CLASS style guide please, and write your code to make it indistinguishable from the rest of the code in the library. That is the only real criteria for good style: it's invisible.
1127
1128Don't include system headers in source files. The right place for these is CZMQ.
1129
1130Do read your code after you write it and ask, "Can I make this simpler?" We do use a nice minimalist and yet readable style. Learn it, adopt it, use it.
1131
1132Before opening a pull request read our [contribution guidelines](https://github.com/zeromq/zyre/blob/master/CONTRIBUTING.md). Thanks!
1133
1134### This Document
1135
1136_This documentation was generated from zyre/README.txt using [Gitdown](https://github.com/zeromq/gitdown)_
1137