1ZGOSSIP(3) CZMQ Manual ZGOSSIP(3)
2
3
4
6 zgossip - Class for decentralized configuration management
7
9 // To work with zgossip, use the CZMQ zactor API:
10 //
11 // Create new zgossip instance, passing logging prefix:
12 //
13 // zactor_t *zgossip = zactor_new (zgossip, "myname");
14 //
15 // Destroy zgossip instance
16 //
17 // zactor_destroy (&zgossip);
18 //
19 // Enable verbose logging of commands and activity:
20 //
21 // zstr_send (zgossip, "VERBOSE");
22 //
23 // Bind zgossip to specified endpoint. TCP endpoints may specify
24 // the port number as "*" to aquire an ephemeral port:
25 //
26 // zstr_sendx (zgossip, "BIND", endpoint, NULL);
27 //
28 // Return assigned port number, specifically when BIND was done using an
29 // an ephemeral port:
30 //
31 // zstr_sendx (zgossip, "PORT", NULL);
32 // char *command, *port_str;
33 // zstr_recvx (zgossip, &command, &port_str, NULL);
34 // assert (streq (command, "PORT"));
35 //
36 // Specify configuration file to load, overwriting any previous loaded
37 // configuration file or options:
38 //
39 // zstr_sendx (zgossip, "LOAD", filename, NULL);
40 //
41 // Set configuration path value:
42 //
43 // zstr_sendx (zgossip, "SET", path, value, NULL);
44 //
45 // Save configuration data to config file on disk:
46 //
47 // zstr_sendx (zgossip, "SAVE", filename, NULL);
48 //
49 // Send zmsg_t instance to zgossip:
50 //
51 // zactor_send (zgossip, &msg);
52 //
53 // Receive zmsg_t instance from zgossip:
54 //
55 // zmsg_t *msg = zactor_recv (zgossip);
56 //
57 // This is the zgossip constructor as a zactor_fn:
58 //
59 CZMQ_EXPORT void
60 zgossip (zsock_t *pipe, void *args);
61
62 // Self test of this class
63 CZMQ_EXPORT void
64 zgossip_test (bool verbose);
65 Please add '@interface' section in './../src/zgossip.c'.
66
68 Implements a gossip protocol for decentralized configuration
69 management. Your applications nodes form a loosely connected network
70 (which can have cycles), and publish name/value tuples. Each node
71 re-distributes the new tuples it receives, so that the entire network
72 eventually achieves a consistent state. The current design does not
73 expire tuples.
74
75 Provides these commands (sent as multipart strings to the actor):
76
77 · BIND endpoint — binds the gossip service to specified endpoint
78
79 · PORT — returns the last TCP port, if any, used for binding
80
81 · LOAD configfile — load configuration from specified file
82
83 · SET configpath value — set configuration path = value
84
85 · SAVE configfile — save configuration to specified file
86
87 · CONNECT endpoint — connect the gossip service to the specified peer
88
89 · PUBLISH key value — publish a key/value pair to the gossip cluster
90
91 · STATUS — return number of key/value pairs held by gossip service
92
93 · ZAP DOMAIN domain — set the ZAP DOMAIN domain = value
94
95 Returns these messages:
96
97 · PORT number — reply to PORT command
98
99 · STATUS number — reply to STATUS command
100
101 · DELIVER key value — new tuple delivered from network
102
103 The gossip protocol distributes information around a loosely-connected
104 network of gossip services. The information consists of name/value
105 pairs published by applications at any point in the network. The goal
106 of the gossip protocol is to create eventual consistency between all
107 the using applications.
108
109 The name/value pairs (tuples) can be used for configuration data, for
110 status updates, for presence, or for discovery. When used for
111 discovery, the gossip protocol works as an alternative to e.g. UDP
112 beaconing.
113
114 The gossip network consists of a set of loosely-coupled nodes that
115 exchange tuples. Nodes can be connected across arbitrary transports, so
116 the gossip network can have nodes that communicate over inproc, over
117 IPC, and/or over TCP, at the same time.
118
119 Each node runs the same stack, which is a server-client hybrid using a
120 modified Harmony pattern (from Chapter 8 of the Guide):
121 http://zguide.zeromq.org/page:all#True-Peer-Connectivity-Harmony-Pattern
122
123 Each node provides a ROUTER socket that accepts client connections on
124 an key defined by the application via a BIND command. The state machine
125 for these connections is in zgossip.xml, and the generated code is in
126 zgossip_engine.inc.
127
128 Each node additionally creates outbound connections via DEALER sockets
129 to a set of servers ("remotes"), and under control of the calling app,
130 which sends CONNECT commands for each configured remote.
131
132 The messages between client and server are defined in zgossip_msg.xml.
133 We built this stack using the zeromq/zproto toolkit.
134
135 To join the gossip network, a node connects to one or more peers. Each
136 peer acts as a forwarder. This loosely-coupled network can scale to
137 thousands of nodes. However the gossip protocol is NOT designed to be
138 efficient, and should not be used for application data, as the same
139 tuples may be sent many times across the network.
140
141 The basic logic of the gossip service is to accept PUBLISH messages
142 from its owning application, and to forward these to every remote, and
143 every client it talks to. When a node gets a duplicate tuple, it throws
144 it away. When a node gets a new tuple, it stores it, and forwards it as
145 just described.
146
147 At present there is no way to expire tuples from the network.
148
149 The assumptions in this design are:
150
151 · The data set is slow-changing. Thus, the cost of the gossip
152 protocol is irrelevant with respect to other traffic.
153
155 From zgossip_test method.
156
157 // Test basic client-to-server operation of the protocol
158 zactor_t *server = zactor_new (zgossip, "server");
159 assert (server);
160 if (verbose)
161 zstr_send (server, "VERBOSE");
162 zstr_sendx (server, "BIND", "inproc://zgossip", NULL);
163
164 zsock_t *client = zsock_new (ZMQ_DEALER);
165 assert (client);
166 zsock_set_rcvtimeo (client, 2000);
167 int rc = zsock_connect (client, "inproc://zgossip");
168 assert (rc == 0);
169
170 // Send HELLO, which gets no message
171 zgossip_msg_t *message = zgossip_msg_new ();
172 zgossip_msg_set_id (message, ZGOSSIP_MSG_HELLO);
173 zgossip_msg_send (message, client);
174
175 // Send PING, expect PONG back
176 zgossip_msg_set_id (message, ZGOSSIP_MSG_PING);
177 zgossip_msg_send (message, client);
178 zgossip_msg_recv (message, client);
179 assert (zgossip_msg_id (message) == ZGOSSIP_MSG_PONG);
180 zgossip_msg_destroy (&message);
181
182 zactor_destroy (&server);
183 zsock_destroy (&client);
184
185 // Test peer-to-peer operations
186 zactor_t *base = zactor_new (zgossip, "base");
187 assert (base);
188 if (verbose)
189 zstr_send (base, "VERBOSE");
190 // Set a 100msec timeout on clients so we can test expiry
191 zstr_sendx (base, "SET", "server/timeout", "100", NULL);
192 zstr_sendx (base, "BIND", "inproc://base", NULL);
193
194 zactor_t *alpha = zactor_new (zgossip, "alpha");
195 assert (alpha);
196 zstr_sendx (alpha, "CONNECT", "inproc://base", NULL);
197 zstr_sendx (alpha, "PUBLISH", "inproc://alpha-1", "service1", NULL);
198 zstr_sendx (alpha, "PUBLISH", "inproc://alpha-2", "service2", NULL);
199
200 zactor_t *beta = zactor_new (zgossip, "beta");
201 assert (beta);
202 zstr_sendx (beta, "CONNECT", "inproc://base", NULL);
203 zstr_sendx (beta, "PUBLISH", "inproc://beta-1", "service1", NULL);
204 zstr_sendx (beta, "PUBLISH", "inproc://beta-2", "service2", NULL);
205
206 // got nothing
207 zclock_sleep (200);
208
209 zstr_send (alpha, "STATUS");
210 char *command, *status, *key, *value;
211
212 zstr_recvx (alpha, &command, &key, &value, NULL);
213 assert (streq (command, "DELIVER"));
214 assert (streq (key, "inproc://alpha-1"));
215 assert (streq (value, "service1"));
216 zstr_free (&command);
217 zstr_free (&key);
218 zstr_free (&value);
219
220 zstr_recvx (alpha, &command, &key, &value, NULL);
221 assert (streq (command, "DELIVER"));
222 assert (streq (key, "inproc://alpha-2"));
223 assert (streq (value, "service2"));
224 zstr_free (&command);
225 zstr_free (&key);
226 zstr_free (&value);
227
228 zstr_recvx (alpha, &command, &key, &value, NULL);
229 assert (streq (command, "DELIVER"));
230 assert (streq (key, "inproc://beta-1"));
231 assert (streq (value, "service1"));
232 zstr_free (&command);
233 zstr_free (&key);
234 zstr_free (&value);
235
236 zstr_recvx (alpha, &command, &key, &value, NULL);
237 assert (streq (command, "DELIVER"));
238 assert (streq (key, "inproc://beta-2"));
239 assert (streq (value, "service2"));
240 zstr_free (&command);
241 zstr_free (&key);
242 zstr_free (&value);
243
244 zstr_recvx (alpha, &command, &status, NULL);
245 assert (streq (command, "STATUS"));
246 assert (atoi (status) == 4);
247 zstr_free (&command);
248 zstr_free (&status);
249
250 zactor_destroy (&base);
251 zactor_destroy (&alpha);
252 zactor_destroy (&beta);
253
254 #ifdef CZMQ_BUILD_DRAFT_API
255 // curve
256 if (zsys_has_curve()) {
257 if (verbose)
258 printf("testing CURVE support");
259 zclock_sleep (2000);
260 zactor_t *auth = zactor_new(zauth, NULL);
261 assert (auth);
262 if (verbose) {
263 zstr_sendx (auth, "VERBOSE", NULL);
264 zsock_wait (auth);
265 }
266 zstr_sendx(auth,"ALLOW","127.0.0.1",NULL);
267 zsock_wait(auth);
268 zstr_sendx (auth, "CURVE", CURVE_ALLOW_ANY, NULL);
269 zsock_wait (auth);
270
271 server = zactor_new (zgossip, "server");
272 if (verbose)
273 zstr_send (server, "VERBOSE");
274 assert (server);
275
276 zcert_t *client1_cert = zcert_new ();
277 zcert_t *server_cert = zcert_new ();
278
279 zstr_sendx (server, "SET PUBLICKEY", zcert_public_txt (server_cert), NULL);
280 zstr_sendx (server, "SET SECRETKEY", zcert_secret_txt (server_cert), NULL);
281 zstr_sendx (server, "ZAP DOMAIN", "TEST", NULL);
282
283 zstr_sendx (server, "BIND", "tcp://127.0.0.1:*", NULL);
284 zstr_sendx (server, "PORT", NULL);
285 zstr_recvx (server, &command, &value, NULL);
286 assert (streq (command, "PORT"));
287 int port = atoi (value);
288 zstr_free (&command);
289 zstr_free (&value);
290 char endpoint [32];
291 sprintf (endpoint, "tcp://127.0.0.1:%d", port);
292
293 zactor_t *client1 = zactor_new (zgossip, "client");
294 if (verbose)
295 zstr_send (client1, "VERBOSE");
296 assert (client1);
297
298 zstr_sendx (client1, "SET PUBLICKEY", zcert_public_txt (client1_cert), NULL);
299 zstr_sendx (client1, "SET SECRETKEY", zcert_secret_txt (client1_cert), NULL);
300 zstr_sendx (client1, "ZAP DOMAIN", "TEST", NULL);
301
302 const char *public_txt = zcert_public_txt (server_cert);
303 zstr_sendx (client1, "CONNECT", endpoint, public_txt, NULL);
304 zstr_sendx (client1, "PUBLISH", "tcp://127.0.0.1:9001", "service1", NULL);
305
306 zclock_sleep (500);
307
308 zstr_send (server, "STATUS");
309 zclock_sleep (500);
310
311 zstr_recvx (server, &command, &key, &value, NULL);
312 assert (streq (command, "DELIVER"));
313 assert (streq (value, "service1"));
314
315 zstr_free (&command);
316 zstr_free (&key);
317 zstr_free (&value);
318
319 zstr_sendx (client1, "$TERM", NULL);
320 zstr_sendx (server, "$TERM", NULL);
321
322 zclock_sleep(500);
323
324 zcert_destroy (&client1_cert);
325 zcert_destroy (&server_cert);
326
327 zactor_destroy (&client1);
328 zactor_destroy (&server);
329 zactor_destroy (&auth);
330 }
331 #endif
332
333 #if defined (__WINDOWS__)
334 zsys_shutdown();
335 #endif
336
337
339 The czmq manual was written by the authors in the AUTHORS file.
340
342 Main web site:
343
344 Report bugs to the email <zeromq-dev@lists.zeromq.org[1]>
345
347 Copyright (c) the Contributors as noted in the AUTHORS file. This file
348 is part of CZMQ, the high-level C binding for 0MQ:
349 http://czmq.zeromq.org. This Source Code Form is subject to the terms
350 of the Mozilla Public License, v. 2.0. If a copy of the MPL was not
351 distributed with this file, You can obtain one at
352 http://mozilla.org/MPL/2.0/. LICENSE included with the czmq
353 distribution.
354
356 1. zeromq-dev@lists.zeromq.org
357 mailto:zeromq-dev@lists.zeromq.org
358
359
360
361CZMQ 4.1.1 01/31/2019 ZGOSSIP(3)