czmq-ffi-gen 0.9.2-x64-mingw32

Sign up to get free protection for your applications and to get access to all the features.
Files changed (118) hide show
  1. checksums.yaml +7 -0
  2. data/AUTHORS +1 -0
  3. data/CHANGES.md +92 -0
  4. data/Gemfile +2 -0
  5. data/LICENSE +14 -0
  6. data/README.md +112 -0
  7. data/lib/czmq-ffi-gen.rb +7 -0
  8. data/lib/czmq-ffi-gen/czmq/ffi.rb +1210 -0
  9. data/lib/czmq-ffi-gen/czmq/ffi/version.rb +15 -0
  10. data/lib/czmq-ffi-gen/czmq/ffi/zactor.rb +186 -0
  11. data/lib/czmq-ffi-gen/czmq/ffi/zarmour.rb +286 -0
  12. data/lib/czmq-ffi-gen/czmq/ffi/zcert.rb +307 -0
  13. data/lib/czmq-ffi-gen/czmq/ffi/zcertstore.rb +222 -0
  14. data/lib/czmq-ffi-gen/czmq/ffi/zchunk.rb +388 -0
  15. data/lib/czmq-ffi-gen/czmq/ffi/zclock.rb +140 -0
  16. data/lib/czmq-ffi-gen/czmq/ffi/zconfig.rb +442 -0
  17. data/lib/czmq-ffi-gen/czmq/ffi/zdigest.rb +156 -0
  18. data/lib/czmq-ffi-gen/czmq/ffi/zdir.rb +283 -0
  19. data/lib/czmq-ffi-gen/czmq/ffi/zdir_patch.rb +194 -0
  20. data/lib/czmq-ffi-gen/czmq/ffi/zfile.rb +353 -0
  21. data/lib/czmq-ffi-gen/czmq/ffi/zframe.rb +359 -0
  22. data/lib/czmq-ffi-gen/czmq/ffi/zhash.rb +416 -0
  23. data/lib/czmq-ffi-gen/czmq/ffi/zhashx.rb +659 -0
  24. data/lib/czmq-ffi-gen/czmq/ffi/ziflist.rb +189 -0
  25. data/lib/czmq-ffi-gen/czmq/ffi/zlist.rb +365 -0
  26. data/lib/czmq-ffi-gen/czmq/ffi/zlistx.rb +478 -0
  27. data/lib/czmq-ffi-gen/czmq/ffi/zloop.rb +396 -0
  28. data/lib/czmq-ffi-gen/czmq/ffi/zmsg.rb +515 -0
  29. data/lib/czmq-ffi-gen/czmq/ffi/zpoller.rb +194 -0
  30. data/lib/czmq-ffi-gen/czmq/ffi/zproc.rb +294 -0
  31. data/lib/czmq-ffi-gen/czmq/ffi/zsock.rb +3479 -0
  32. data/lib/czmq-ffi-gen/czmq/ffi/zstr.rb +203 -0
  33. data/lib/czmq-ffi-gen/czmq/ffi/ztimerset.rb +203 -0
  34. data/lib/czmq-ffi-gen/czmq/ffi/ztrie.rb +221 -0
  35. data/lib/czmq-ffi-gen/czmq/ffi/zuuid.rb +227 -0
  36. data/lib/czmq-ffi-gen/errors.rb +12 -0
  37. data/lib/czmq-ffi-gen/gem_version.rb +5 -0
  38. data/lib/czmq-ffi-gen/legacy.rb +16 -0
  39. data/lib/czmq-ffi-gen/libzmq.rb +18 -0
  40. data/lib/czmq-ffi-gen/signals.rb +27 -0
  41. data/lib/czmq-ffi-gen/vendor.rb +5 -0
  42. data/lib/czmq-ffi-gen/versions.rb +19 -0
  43. data/vendor/local/bin/inproc_lat.exe +0 -0
  44. data/vendor/local/bin/inproc_thr.exe +0 -0
  45. data/vendor/local/bin/libczmq.dll +0 -0
  46. data/vendor/local/bin/libgcc_s_seh-1.dll +0 -0
  47. data/vendor/local/bin/libstdc++-6.dll +0 -0
  48. data/vendor/local/bin/libzmq.dll +0 -0
  49. data/vendor/local/bin/local_lat.exe +0 -0
  50. data/vendor/local/bin/local_thr.exe +0 -0
  51. data/vendor/local/bin/remote_lat.exe +0 -0
  52. data/vendor/local/bin/remote_thr.exe +0 -0
  53. data/vendor/local/include/czmq.h +31 -0
  54. data/vendor/local/include/czmq_library.h +199 -0
  55. data/vendor/local/include/czmq_prelude.h +641 -0
  56. data/vendor/local/include/readme.txt +83 -0
  57. data/vendor/local/include/sha1.h +76 -0
  58. data/vendor/local/include/sha1.inc_c +335 -0
  59. data/vendor/local/include/slre.h +92 -0
  60. data/vendor/local/include/slre.inc_c +660 -0
  61. data/vendor/local/include/zactor.h +76 -0
  62. data/vendor/local/include/zarmour.h +114 -0
  63. data/vendor/local/include/zauth.h +100 -0
  64. data/vendor/local/include/zauth_v2.h +88 -0
  65. data/vendor/local/include/zbeacon.h +86 -0
  66. data/vendor/local/include/zbeacon_v2.h +75 -0
  67. data/vendor/local/include/zcert.h +136 -0
  68. data/vendor/local/include/zcertstore.h +100 -0
  69. data/vendor/local/include/zchunk.h +163 -0
  70. data/vendor/local/include/zclock.h +73 -0
  71. data/vendor/local/include/zconfig.h +185 -0
  72. data/vendor/local/include/zctx.h +107 -0
  73. data/vendor/local/include/zdigest.h +65 -0
  74. data/vendor/local/include/zdir.h +149 -0
  75. data/vendor/local/include/zdir_patch.h +82 -0
  76. data/vendor/local/include/zfile.h +177 -0
  77. data/vendor/local/include/zframe.h +176 -0
  78. data/vendor/local/include/zgossip.h +95 -0
  79. data/vendor/local/include/zgossip_engine.inc +927 -0
  80. data/vendor/local/include/zgossip_msg.h +129 -0
  81. data/vendor/local/include/zhash.h +195 -0
  82. data/vendor/local/include/zhash_primes.inc +329 -0
  83. data/vendor/local/include/zhashx.h +298 -0
  84. data/vendor/local/include/ziflist.h +77 -0
  85. data/vendor/local/include/zlist.h +158 -0
  86. data/vendor/local/include/zlistx.h +205 -0
  87. data/vendor/local/include/zloop.h +168 -0
  88. data/vendor/local/include/zmonitor.h +73 -0
  89. data/vendor/local/include/zmonitor_v2.h +56 -0
  90. data/vendor/local/include/zmq.h +617 -0
  91. data/vendor/local/include/zmq_utils.h +48 -0
  92. data/vendor/local/include/zmsg.h +280 -0
  93. data/vendor/local/include/zmutex.h +55 -0
  94. data/vendor/local/include/zpoller.h +92 -0
  95. data/vendor/local/include/zproc.h +168 -0
  96. data/vendor/local/include/zproxy.h +111 -0
  97. data/vendor/local/include/zproxy_v2.h +62 -0
  98. data/vendor/local/include/zrex.h +82 -0
  99. data/vendor/local/include/zsock.h +912 -0
  100. data/vendor/local/include/zsock_option.inc +4126 -0
  101. data/vendor/local/include/zsocket.h +110 -0
  102. data/vendor/local/include/zsockopt.h +256 -0
  103. data/vendor/local/include/zstr.h +110 -0
  104. data/vendor/local/include/zsys.h +386 -0
  105. data/vendor/local/include/zthread.h +50 -0
  106. data/vendor/local/include/ztimerset.h +90 -0
  107. data/vendor/local/include/ztrie.h +106 -0
  108. data/vendor/local/include/zuuid.h +96 -0
  109. data/vendor/local/lib/libczmq.dll.a +0 -0
  110. data/vendor/local/lib/liblibzmq.dll.a +0 -0
  111. data/vendor/local/lib/libzmq-static.a +0 -0
  112. data/vendor/local/lib/pkgconfig/libczmq.pc +23 -0
  113. data/vendor/local/lib/pkgconfig/libzmq.pc +11 -0
  114. data/vendor/local/share/zmq/AUTHORS.txt +147 -0
  115. data/vendor/local/share/zmq/COPYING.LESSER.txt +181 -0
  116. data/vendor/local/share/zmq/COPYING.txt +674 -0
  117. data/vendor/local/share/zmq/NEWS.txt +978 -0
  118. metadata +230 -0
@@ -0,0 +1,927 @@
1
+ /* =========================================================================
2
+ zgossip_engine - zgossip engine
3
+
4
+ ** WARNING *************************************************************
5
+ THIS SOURCE FILE IS 100% GENERATED. If you edit this file, you will lose
6
+ your changes at the next build cycle. This is great for temporary printf
7
+ statements. DO NOT MAKE ANY CHANGES YOU WISH TO KEEP. The correct places
8
+ for commits are:
9
+
10
+ * The XML model used for this code generation: zgossip.xml, or
11
+ * The code generation script that built this file: zproto_server_c
12
+ ************************************************************************
13
+ Copyright (c) the Contributors as noted in the AUTHORS file.
14
+ This file is part of CZMQ, the high-level C binding for 0MQ:
15
+ http://czmq.zeromq.org.
16
+
17
+ This Source Code Form is subject to the terms of the Mozilla Public
18
+ License, v. 2.0. If a copy of the MPL was not distributed with this
19
+ file, You can obtain one at http://mozilla.org/MPL/2.0/.
20
+ =========================================================================
21
+ */
22
+
23
+ // ---------------------------------------------------------------------------
24
+ // State machine constants
25
+
26
+ typedef enum {
27
+ start_state = 1,
28
+ have_tuple_state = 2,
29
+ connected_state = 3,
30
+ external_state = 4
31
+ } state_t;
32
+
33
+ typedef enum {
34
+ NULL_event = 0,
35
+ terminate_event = 1,
36
+ hello_event = 2,
37
+ ok_event = 3,
38
+ finished_event = 4,
39
+ publish_event = 5,
40
+ forward_event = 6,
41
+ ping_event = 7,
42
+ expired_event = 8
43
+ } event_t;
44
+
45
+ // Names for state machine logging and error reporting
46
+ static char *
47
+ s_state_name [] = {
48
+ "(NONE)",
49
+ "start",
50
+ "have tuple",
51
+ "connected",
52
+ "external"
53
+ };
54
+
55
+ static char *
56
+ s_event_name [] = {
57
+ "(NONE)",
58
+ "terminate",
59
+ "HELLO",
60
+ "ok",
61
+ "finished",
62
+ "PUBLISH",
63
+ "forward",
64
+ "PING",
65
+ "expired"
66
+ };
67
+
68
+ // ---------------------------------------------------------------------------
69
+ // Context for the whole server task. This embeds the application-level
70
+ // server context at its start (the entire structure, not a reference),
71
+ // so we can cast a pointer between server_t and s_server_t arbitrarily.
72
+
73
+ typedef struct {
74
+ server_t server; // Application-level server context
75
+ zsock_t *pipe; // Socket to back to caller API
76
+ zsock_t *router; // Socket to talk to clients
77
+ int port; // Server port bound to
78
+ zloop_t *loop; // Reactor for server sockets
79
+ zgossip_msg_t *message; // Message received or sent
80
+ zhash_t *clients; // Clients we're connected to
81
+ zconfig_t *config; // Configuration tree
82
+ uint client_id; // Client identifier counter
83
+ size_t timeout; // Default client expiry timeout
84
+ bool verbose; // Verbose logging enabled?
85
+ char *log_prefix; // Default log prefix
86
+ } s_server_t;
87
+
88
+
89
+ // ---------------------------------------------------------------------------
90
+ // Context for each connected client. This embeds the application-level
91
+ // client context at its start (the entire structure, not a reference),
92
+ // so we can cast a pointer between client_t and s_client_t arbitrarily.
93
+
94
+ typedef struct {
95
+ client_t client; // Application-level client context
96
+ s_server_t *server; // Parent server context
97
+ char *hashkey; // Key into server->clients hash
98
+ zframe_t *routing_id; // Routing_id back to client
99
+ uint unique_id; // Client identifier in server
100
+ state_t state; // Current state
101
+ event_t event; // Current event
102
+ event_t next_event; // The next event
103
+ event_t exception; // Exception event, if any
104
+ int wakeup; // zloop timer for client alarms
105
+ void *ticket; // zloop ticket for client timeouts
106
+ event_t wakeup_event; // Wake up with this event
107
+ char log_prefix [41]; // Log prefix string
108
+ } s_client_t;
109
+
110
+ static int
111
+ server_initialize (server_t *self);
112
+ static void
113
+ server_terminate (server_t *self);
114
+ static zmsg_t *
115
+ server_method (server_t *self, const char *method, zmsg_t *msg);
116
+ static int
117
+ client_initialize (client_t *self);
118
+ static void
119
+ client_terminate (client_t *self);
120
+ static void
121
+ s_client_execute (s_client_t *client, event_t event);
122
+ static int
123
+ s_client_handle_wakeup (zloop_t *loop, int timer_id, void *argument);
124
+ static int
125
+ s_client_handle_ticket (zloop_t *loop, int timer_id, void *argument);
126
+ static void
127
+ get_first_tuple (client_t *self);
128
+ static void
129
+ get_next_tuple (client_t *self);
130
+ static void
131
+ store_tuple_if_new (client_t *self);
132
+ static void
133
+ get_tuple_to_forward (client_t *self);
134
+
135
+ // ---------------------------------------------------------------------------
136
+ // These methods are an internal API for actions
137
+
138
+ // Set the next event, needed in at least one action in an internal
139
+ // state; otherwise the state machine will wait for a message on the
140
+ // router socket and treat that as the event.
141
+
142
+ static void
143
+ engine_set_next_event (client_t *client, event_t event)
144
+ {
145
+ if (client) {
146
+ s_client_t *self = (s_client_t *) client;
147
+ self->next_event = event;
148
+ }
149
+ }
150
+
151
+ // Raise an exception with 'event', halting any actions in progress.
152
+ // Continues execution of actions defined for the exception event.
153
+
154
+ static void
155
+ engine_set_exception (client_t *client, event_t event)
156
+ {
157
+ if (client) {
158
+ s_client_t *self = (s_client_t *) client;
159
+ self->exception = event;
160
+ }
161
+ }
162
+
163
+ // Set wakeup alarm after 'delay' msecs. The next state should
164
+ // handle the wakeup event. The alarm is cancelled on any other
165
+ // event.
166
+
167
+ static void
168
+ engine_set_wakeup_event (client_t *client, size_t delay, event_t event)
169
+ {
170
+ if (client) {
171
+ s_client_t *self = (s_client_t *) client;
172
+ if (self->wakeup) {
173
+ zloop_timer_end (self->server->loop, self->wakeup);
174
+ self->wakeup = 0;
175
+ }
176
+ self->wakeup = zloop_timer (
177
+ self->server->loop, delay, 1, s_client_handle_wakeup, self);
178
+ self->wakeup_event = event;
179
+ }
180
+ }
181
+
182
+ // Execute 'event' on specified client. Use this to send events to
183
+ // other clients. Cancels any wakeup alarm on that client.
184
+
185
+ static void
186
+ engine_send_event (client_t *client, event_t event)
187
+ {
188
+ if (client) {
189
+ s_client_t *self = (s_client_t *) client;
190
+ s_client_execute (self, event);
191
+ }
192
+ }
193
+
194
+ // Execute 'event' on all clients known to the server. If you pass a
195
+ // client argument, that client will not receive the broadcast. If you
196
+ // want to pass any arguments, store them in the server context.
197
+
198
+ static void
199
+ engine_broadcast_event (server_t *server, client_t *client, event_t event)
200
+ {
201
+ if (server) {
202
+ s_server_t *self = (s_server_t *) server;
203
+ zlist_t *keys = zhash_keys (self->clients);
204
+ char *key = (char *) zlist_first (keys);
205
+ while (key) {
206
+ s_client_t *target = (s_client_t *) zhash_lookup (self->clients, key);
207
+ if (target != (s_client_t *) client)
208
+ s_client_execute (target, event);
209
+ key = (char *) zlist_next (keys);
210
+ }
211
+ zlist_destroy (&keys);
212
+ }
213
+ }
214
+
215
+ // Poll actor or zsock for activity, invoke handler on any received
216
+ // message. Handler must be a CZMQ zloop_fn function; receives server
217
+ // as arg.
218
+
219
+ static void
220
+ engine_handle_socket (server_t *server, void *sock, zloop_reader_fn handler)
221
+ {
222
+ if (server) {
223
+ s_server_t *self = (s_server_t *) server;
224
+ // Resolve zactor_t -> zsock_t
225
+ if (zactor_is (sock))
226
+ sock = zactor_sock ((zactor_t *) sock);
227
+ else
228
+ assert (zsock_is (sock));
229
+ if (handler != NULL) {
230
+ int rc = zloop_reader (self->loop, (zsock_t *) sock, handler, self);
231
+ assert (rc == 0);
232
+ zloop_reader_set_tolerant (self->loop, (zsock_t *) sock);
233
+ }
234
+ else
235
+ zloop_reader_end (self->loop, (zsock_t *) sock);
236
+ }
237
+ }
238
+
239
+ // Register monitor function that will be called at regular intervals
240
+ // by the server engine
241
+
242
+ static void
243
+ engine_set_monitor (server_t *server, size_t interval, zloop_timer_fn monitor)
244
+ {
245
+ if (server) {
246
+ s_server_t *self = (s_server_t *) server;
247
+ int rc = zloop_timer (self->loop, interval, 0, monitor, self);
248
+ assert (rc >= 0);
249
+ }
250
+ }
251
+
252
+ // Set log file prefix; this string will be added to log data, to make
253
+ // log data more searchable. The string is truncated to ~20 chars.
254
+
255
+ static void
256
+ engine_set_log_prefix (client_t *client, const char *string)
257
+ {
258
+ if (client) {
259
+ s_client_t *self = (s_client_t *) client;
260
+ snprintf (self->log_prefix, sizeof (self->log_prefix) - 1,
261
+ "%6d:%-33s", self->unique_id, string);
262
+ }
263
+ }
264
+
265
+ // Set a configuration value in the server's configuration tree. The
266
+ // properties this engine uses are: server/verbose, server/timeout, and
267
+ // server/background. You can also configure other abitrary properties.
268
+
269
+ static void
270
+ engine_configure (server_t *server, const char *path, const char *value)
271
+ {
272
+ if (server) {
273
+ s_server_t *self = (s_server_t *) server;
274
+ zconfig_put (self->config, path, value);
275
+ }
276
+ }
277
+
278
+ // Return true if server is running in verbose mode, else return false.
279
+
280
+ static bool
281
+ engine_verbose (server_t *server)
282
+ {
283
+ if (server) {
284
+ s_server_t *self = (s_server_t *) server;
285
+ return self->verbose;
286
+ }
287
+ return false;
288
+ }
289
+
290
+ // Pedantic compilers don't like unused functions, so we call the whole
291
+ // API, passing null references. It's nasty and horrid and sufficient.
292
+
293
+ static void
294
+ s_satisfy_pedantic_compilers (void)
295
+ {
296
+ engine_set_next_event (NULL, NULL_event);
297
+ engine_set_exception (NULL, NULL_event);
298
+ engine_set_wakeup_event (NULL, 0, NULL_event);
299
+ engine_send_event (NULL, NULL_event);
300
+ engine_broadcast_event (NULL, NULL, NULL_event);
301
+ engine_handle_socket (NULL, 0, NULL);
302
+ engine_set_monitor (NULL, 0, NULL);
303
+ engine_set_log_prefix (NULL, NULL);
304
+ engine_configure (NULL, NULL, NULL);
305
+ engine_verbose (NULL);
306
+ }
307
+
308
+
309
+ // ---------------------------------------------------------------------------
310
+ // Generic methods on protocol messages
311
+ // TODO: replace with lookup table, since ID is one byte
312
+
313
+ static event_t
314
+ s_protocol_event (zgossip_msg_t *message)
315
+ {
316
+ assert (message);
317
+ switch (zgossip_msg_id (message)) {
318
+ case ZGOSSIP_MSG_HELLO:
319
+ return hello_event;
320
+ break;
321
+ case ZGOSSIP_MSG_PUBLISH:
322
+ return publish_event;
323
+ break;
324
+ case ZGOSSIP_MSG_PING:
325
+ return ping_event;
326
+ break;
327
+ default:
328
+ // Invalid zgossip_msg_t
329
+ return terminate_event;
330
+ }
331
+ }
332
+
333
+
334
+ // ---------------------------------------------------------------------------
335
+ // Client methods
336
+
337
+ static s_client_t *
338
+ s_client_new (s_server_t *server, zframe_t *routing_id)
339
+ {
340
+ s_client_t *self = (s_client_t *) zmalloc (sizeof (s_client_t));
341
+ assert (self);
342
+ assert ((s_client_t *) &self->client == self);
343
+
344
+ self->server = server;
345
+ self->hashkey = zframe_strhex (routing_id);
346
+ self->routing_id = zframe_dup (routing_id);
347
+ self->unique_id = server->client_id++;
348
+ engine_set_log_prefix (&self->client, server->log_prefix);
349
+
350
+ self->client.server = (server_t *) server;
351
+ self->client.message = server->message;
352
+
353
+ // If expiry timers are being used, create client ticket
354
+ if (server->timeout)
355
+ self->ticket = zloop_ticket (server->loop, s_client_handle_ticket, self);
356
+ // Give application chance to initialize and set next event
357
+ self->state = start_state;
358
+ self->event = NULL_event;
359
+ client_initialize (&self->client);
360
+ return self;
361
+ }
362
+
363
+ static void
364
+ s_client_destroy (s_client_t **self_p)
365
+ {
366
+ assert (self_p);
367
+ if (*self_p) {
368
+ s_client_t *self = *self_p;
369
+ if (self->wakeup)
370
+ zloop_timer_end (self->server->loop, self->wakeup);
371
+ if (self->ticket)
372
+ zloop_ticket_delete (self->server->loop, self->ticket);
373
+ zframe_destroy (&self->routing_id);
374
+ // Provide visual clue if application misuses client reference
375
+ engine_set_log_prefix (&self->client, "*** TERMINATED ***");
376
+ client_terminate (&self->client);
377
+ free (self->hashkey);
378
+ free (self);
379
+ *self_p = NULL;
380
+ }
381
+ }
382
+
383
+ // Callback when we remove client from 'clients' hash table
384
+ static void
385
+ s_client_free (void *argument)
386
+ {
387
+ s_client_t *client = (s_client_t *) argument;
388
+ s_client_destroy (&client);
389
+ }
390
+
391
+
392
+ // Execute state machine as long as we have events
393
+
394
+ static void
395
+ s_client_execute (s_client_t *self, event_t event)
396
+ {
397
+ self->next_event = event;
398
+ // Cancel wakeup timer, if any was pending
399
+ if (self->wakeup) {
400
+ zloop_timer_end (self->server->loop, self->wakeup);
401
+ self->wakeup = 0;
402
+ }
403
+ while (self->next_event > 0) {
404
+ self->event = self->next_event;
405
+ self->next_event = NULL_event;
406
+ self->exception = NULL_event;
407
+ if (self->server->verbose) {
408
+ zsys_debug ("%s: %s:",
409
+ self->log_prefix, s_state_name [self->state]);
410
+ zsys_debug ("%s: %s",
411
+ self->log_prefix, s_event_name [self->event]);
412
+ }
413
+ switch (self->state) {
414
+ case start_state:
415
+ if (self->event == hello_event) {
416
+ if (!self->exception) {
417
+ // get first tuple
418
+ if (self->server->verbose)
419
+ zsys_debug ("%s: $ get first tuple", self->log_prefix);
420
+ get_first_tuple (&self->client);
421
+ }
422
+ if (!self->exception)
423
+ self->state = have_tuple_state;
424
+ }
425
+ else
426
+ if (self->event == ping_event) {
427
+ if (!self->exception) {
428
+ // send PONG
429
+ if (self->server->verbose)
430
+ zsys_debug ("%s: $ send PONG",
431
+ self->log_prefix);
432
+ zgossip_msg_set_id (self->server->message, ZGOSSIP_MSG_PONG);
433
+ zgossip_msg_set_routing_id (self->server->message, self->routing_id);
434
+ zgossip_msg_send (self->server->message, self->server->router);
435
+ }
436
+ }
437
+ else
438
+ if (self->event == expired_event) {
439
+ if (!self->exception) {
440
+ // terminate
441
+ if (self->server->verbose)
442
+ zsys_debug ("%s: $ terminate", self->log_prefix);
443
+ self->next_event = terminate_event;
444
+ }
445
+ }
446
+ else {
447
+ // Handle unexpected protocol events
448
+ if (!self->exception) {
449
+ // send INVALID
450
+ if (self->server->verbose)
451
+ zsys_debug ("%s: $ send INVALID",
452
+ self->log_prefix);
453
+ zgossip_msg_set_id (self->server->message, ZGOSSIP_MSG_INVALID);
454
+ zgossip_msg_set_routing_id (self->server->message, self->routing_id);
455
+ zgossip_msg_send (self->server->message, self->server->router);
456
+ }
457
+ if (!self->exception) {
458
+ // terminate
459
+ if (self->server->verbose)
460
+ zsys_debug ("%s: $ terminate", self->log_prefix);
461
+ self->next_event = terminate_event;
462
+ }
463
+ }
464
+ break;
465
+
466
+ case have_tuple_state:
467
+ if (self->event == ok_event) {
468
+ if (!self->exception) {
469
+ // send PUBLISH
470
+ if (self->server->verbose)
471
+ zsys_debug ("%s: $ send PUBLISH",
472
+ self->log_prefix);
473
+ zgossip_msg_set_id (self->server->message, ZGOSSIP_MSG_PUBLISH);
474
+ zgossip_msg_set_routing_id (self->server->message, self->routing_id);
475
+ zgossip_msg_send (self->server->message, self->server->router);
476
+ }
477
+ if (!self->exception) {
478
+ // get next tuple
479
+ if (self->server->verbose)
480
+ zsys_debug ("%s: $ get next tuple", self->log_prefix);
481
+ get_next_tuple (&self->client);
482
+ }
483
+ }
484
+ else
485
+ if (self->event == finished_event) {
486
+ if (!self->exception)
487
+ self->state = connected_state;
488
+ }
489
+ else {
490
+ // Handle unexpected internal events
491
+ zsys_warning ("%s: unhandled event %s in %s",
492
+ self->log_prefix,
493
+ s_event_name [self->event],
494
+ s_state_name [self->state]);
495
+ assert (false);
496
+ }
497
+ break;
498
+
499
+ case connected_state:
500
+ if (self->event == publish_event) {
501
+ if (!self->exception) {
502
+ // store tuple if new
503
+ if (self->server->verbose)
504
+ zsys_debug ("%s: $ store tuple if new", self->log_prefix);
505
+ store_tuple_if_new (&self->client);
506
+ }
507
+ }
508
+ else
509
+ if (self->event == forward_event) {
510
+ if (!self->exception) {
511
+ // get tuple to forward
512
+ if (self->server->verbose)
513
+ zsys_debug ("%s: $ get tuple to forward", self->log_prefix);
514
+ get_tuple_to_forward (&self->client);
515
+ }
516
+ if (!self->exception) {
517
+ // send PUBLISH
518
+ if (self->server->verbose)
519
+ zsys_debug ("%s: $ send PUBLISH",
520
+ self->log_prefix);
521
+ zgossip_msg_set_id (self->server->message, ZGOSSIP_MSG_PUBLISH);
522
+ zgossip_msg_set_routing_id (self->server->message, self->routing_id);
523
+ zgossip_msg_send (self->server->message, self->server->router);
524
+ }
525
+ }
526
+ else
527
+ if (self->event == ping_event) {
528
+ if (!self->exception) {
529
+ // send PONG
530
+ if (self->server->verbose)
531
+ zsys_debug ("%s: $ send PONG",
532
+ self->log_prefix);
533
+ zgossip_msg_set_id (self->server->message, ZGOSSIP_MSG_PONG);
534
+ zgossip_msg_set_routing_id (self->server->message, self->routing_id);
535
+ zgossip_msg_send (self->server->message, self->server->router);
536
+ }
537
+ }
538
+ else
539
+ if (self->event == expired_event) {
540
+ if (!self->exception) {
541
+ // terminate
542
+ if (self->server->verbose)
543
+ zsys_debug ("%s: $ terminate", self->log_prefix);
544
+ self->next_event = terminate_event;
545
+ }
546
+ }
547
+ else {
548
+ // Handle unexpected protocol events
549
+ if (!self->exception) {
550
+ // send INVALID
551
+ if (self->server->verbose)
552
+ zsys_debug ("%s: $ send INVALID",
553
+ self->log_prefix);
554
+ zgossip_msg_set_id (self->server->message, ZGOSSIP_MSG_INVALID);
555
+ zgossip_msg_set_routing_id (self->server->message, self->routing_id);
556
+ zgossip_msg_send (self->server->message, self->server->router);
557
+ }
558
+ if (!self->exception) {
559
+ // terminate
560
+ if (self->server->verbose)
561
+ zsys_debug ("%s: $ terminate", self->log_prefix);
562
+ self->next_event = terminate_event;
563
+ }
564
+ }
565
+ break;
566
+
567
+ case external_state:
568
+ if (self->event == ping_event) {
569
+ if (!self->exception) {
570
+ // send PONG
571
+ if (self->server->verbose)
572
+ zsys_debug ("%s: $ send PONG",
573
+ self->log_prefix);
574
+ zgossip_msg_set_id (self->server->message, ZGOSSIP_MSG_PONG);
575
+ zgossip_msg_set_routing_id (self->server->message, self->routing_id);
576
+ zgossip_msg_send (self->server->message, self->server->router);
577
+ }
578
+ }
579
+ else
580
+ if (self->event == expired_event) {
581
+ if (!self->exception) {
582
+ // terminate
583
+ if (self->server->verbose)
584
+ zsys_debug ("%s: $ terminate", self->log_prefix);
585
+ self->next_event = terminate_event;
586
+ }
587
+ }
588
+ else {
589
+ // Handle unexpected protocol events
590
+ if (!self->exception) {
591
+ // send INVALID
592
+ if (self->server->verbose)
593
+ zsys_debug ("%s: $ send INVALID",
594
+ self->log_prefix);
595
+ zgossip_msg_set_id (self->server->message, ZGOSSIP_MSG_INVALID);
596
+ zgossip_msg_set_routing_id (self->server->message, self->routing_id);
597
+ zgossip_msg_send (self->server->message, self->server->router);
598
+ }
599
+ if (!self->exception) {
600
+ // terminate
601
+ if (self->server->verbose)
602
+ zsys_debug ("%s: $ terminate", self->log_prefix);
603
+ self->next_event = terminate_event;
604
+ }
605
+ }
606
+ break;
607
+ }
608
+ // If we had an exception event, interrupt normal programming
609
+ if (self->exception) {
610
+ if (self->server->verbose)
611
+ zsys_debug ("%s: ! %s",
612
+ self->log_prefix, s_event_name [self->exception]);
613
+
614
+ self->next_event = self->exception;
615
+ }
616
+ if (self->next_event == terminate_event) {
617
+ // Automatically calls s_client_destroy
618
+ zhash_delete (self->server->clients, self->hashkey);
619
+ break;
620
+ }
621
+ else
622
+ if (self->server->verbose)
623
+ zsys_debug ("%s: > %s",
624
+ self->log_prefix, s_state_name [self->state]);
625
+ }
626
+ }
627
+
628
+ // zloop callback when client ticket expires
629
+
630
+ static int
631
+ s_client_handle_ticket (zloop_t *loop, int timer_id, void *argument)
632
+ {
633
+ s_client_t *self = (s_client_t *) argument;
634
+ self->ticket = NULL; // Ticket is now dead
635
+ s_client_execute (self, expired_event);
636
+ return 0;
637
+ }
638
+
639
+ // zloop callback when client wakeup timer expires
640
+
641
+ static int
642
+ s_client_handle_wakeup (zloop_t *loop, int timer_id, void *argument)
643
+ {
644
+ s_client_t *self = (s_client_t *) argument;
645
+ s_client_execute (self, self->wakeup_event);
646
+ return 0;
647
+ }
648
+
649
+
650
+ // Server methods
651
+
652
+ static void
653
+ s_server_config_global (s_server_t *self)
654
+ {
655
+ // Built-in server configuration options
656
+ //
657
+ // If we didn't already set verbose, check if the config tree wants it
658
+ if (!self->verbose
659
+ && atoi (zconfig_resolve (self->config, "server/verbose", "0")))
660
+ self->verbose = true;
661
+
662
+ // Default client timeout is 60 seconds
663
+ self->timeout = atoi (
664
+ zconfig_resolve (self->config, "server/timeout", "60000"));
665
+ zloop_set_ticket_delay (self->loop, self->timeout);
666
+
667
+ // Do we want to run server in the background?
668
+ int background = atoi (
669
+ zconfig_resolve (self->config, "server/background", "0"));
670
+ if (!background)
671
+ zsys_set_logstream (stdout);
672
+ }
673
+
674
+ static s_server_t *
675
+ s_server_new (zsock_t *pipe)
676
+ {
677
+ s_server_t *self = (s_server_t *) zmalloc (sizeof (s_server_t));
678
+ assert (self);
679
+ assert ((s_server_t *) &self->server == self);
680
+
681
+ self->pipe = pipe;
682
+ self->router = zsock_new (ZMQ_ROUTER);
683
+ assert (self->router);
684
+ // By default the socket will discard outgoing messages above the
685
+ // HWM of 1,000. This isn't helpful for high-volume streaming. We
686
+ // will use a unbounded queue here. If applications need to guard
687
+ // against queue overflow, they should use a credit-based flow
688
+ // control scheme.
689
+ zsock_set_unbounded (self->router);
690
+ self->message = zgossip_msg_new ();
691
+ self->clients = zhash_new ();
692
+ self->config = zconfig_new ("root", NULL);
693
+ self->loop = zloop_new ();
694
+ srandom ((unsigned int) zclock_time ());
695
+ self->client_id = randof (1000);
696
+ s_server_config_global (self);
697
+
698
+ // Initialize application server context
699
+ self->server.pipe = self->pipe;
700
+ self->server.config = self->config;
701
+ server_initialize (&self->server);
702
+
703
+ s_satisfy_pedantic_compilers ();
704
+ return self;
705
+ }
706
+
707
+ static void
708
+ s_server_destroy (s_server_t **self_p)
709
+ {
710
+ assert (self_p);
711
+ if (*self_p) {
712
+ s_server_t *self = *self_p;
713
+ zgossip_msg_destroy (&self->message);
714
+ // Destroy clients before destroying the server
715
+ zhash_destroy (&self->clients);
716
+ server_terminate (&self->server);
717
+ zsock_destroy (&self->router);
718
+ zconfig_destroy (&self->config);
719
+ zloop_destroy (&self->loop);
720
+ free (self);
721
+ *self_p = NULL;
722
+ }
723
+ }
724
+
725
+ // Apply service-specific configuration tree:
726
+ // * apply server configuration
727
+ // * print any echo items in top-level sections
728
+ // * apply sections that match methods
729
+
730
+ static void
731
+ s_server_config_service (s_server_t *self)
732
+ {
733
+ // Apply echo commands and class methods
734
+ zconfig_t *section = zconfig_locate (self->config, "zgossip");
735
+ if (section)
736
+ section = zconfig_child (section);
737
+
738
+ while (section) {
739
+ if (streq (zconfig_name (section), "echo"))
740
+ zsys_notice ("%s", zconfig_value (section));
741
+ else
742
+ if (streq (zconfig_name (section), "bind")) {
743
+ char *endpoint = zconfig_resolve (section, "endpoint", "?");
744
+ if (zsock_bind (self->router, "%s", endpoint) == -1)
745
+ zsys_warning ("could not bind to %s (%s)", endpoint, zmq_strerror (zmq_errno ()));
746
+ }
747
+ #if (ZMQ_VERSION_MAJOR >= 4)
748
+ else
749
+ if (streq (zconfig_name (section), "security")) {
750
+ char *mechanism = zconfig_resolve (section, "mechanism", "null");
751
+ char *domain = zconfig_resolve (section, "domain", NULL);
752
+ if (streq (mechanism, "null")) {
753
+ zsys_notice ("server is using NULL security");
754
+ if (domain)
755
+ zsock_set_zap_domain (self->router, NULL);
756
+ }
757
+ else
758
+ if (streq (mechanism, "plain")) {
759
+ zsys_notice ("server is using PLAIN security");
760
+ zsock_set_plain_server (self->router, 1);
761
+ }
762
+ else
763
+ zsys_warning ("mechanism=%s is not supported", mechanism);
764
+ }
765
+ #endif
766
+ section = zconfig_next (section);
767
+ }
768
+ s_server_config_global (self);
769
+ }
770
+
771
+ // Process message from pipe
772
+
773
+ static int
774
+ s_server_handle_pipe (zloop_t *loop, zsock_t *reader, void *argument)
775
+ {
776
+ s_server_t *self = (s_server_t *) argument;
777
+ zmsg_t *msg = zmsg_recv (self->pipe);
778
+ if (!msg)
779
+ return -1; // Interrupted; exit zloop
780
+ char *method = zmsg_popstr (msg);
781
+ if (self->verbose)
782
+ zsys_debug ("%s: API command=%s", self->log_prefix, method);
783
+
784
+ if (streq (method, "VERBOSE"))
785
+ self->verbose = true;
786
+ else
787
+ if (streq (method, "$TERM")) {
788
+ // Shutdown the engine
789
+ free (method);
790
+ zmsg_destroy (&msg);
791
+ return -1;
792
+ }
793
+ else
794
+ if (streq (method, "BIND")) {
795
+ // Bind to a specified endpoint, which may use an ephemeral port
796
+ char *endpoint = zmsg_popstr (msg);
797
+ self->port = zsock_bind (self->router, "%s", endpoint);
798
+ if (self->port == -1)
799
+ zsys_warning ("could not bind to %s", endpoint);
800
+ free (endpoint);
801
+ }
802
+ else
803
+ if (streq (method, "PORT")) {
804
+ // Return PORT + port number from the last bind, if any
805
+ zstr_sendm (self->pipe, "PORT");
806
+ zstr_sendf (self->pipe, "%d", self->port);
807
+ }
808
+ else // Deprecated method name
809
+ if (streq (method, "LOAD") || streq (method, "CONFIGURE")) {
810
+ char *filename = zmsg_popstr (msg);
811
+ zconfig_destroy (&self->config);
812
+ self->config = zconfig_load (filename);
813
+ if (self->config) {
814
+ s_server_config_service (self);
815
+ self->server.config = self->config;
816
+ }
817
+ else {
818
+ zsys_warning ("cannot load config file '%s'", filename);
819
+ self->config = zconfig_new ("root", NULL);
820
+ }
821
+ free (filename);
822
+ }
823
+ else
824
+ if (streq (method, "SET")) {
825
+ char *path = zmsg_popstr (msg);
826
+ char *value = zmsg_popstr (msg);
827
+ zconfig_put (self->config, path, value);
828
+ if (streq (path, "server/animate")) {
829
+ zsys_warning ("'%s' is deprecated, use VERBOSE command instead", path);
830
+ self->verbose = (atoi (value) == 1);
831
+ }
832
+ s_server_config_global (self);
833
+ free (path);
834
+ free (value);
835
+ }
836
+ else
837
+ if (streq (method, "SAVE")) {
838
+ char *filename = zmsg_popstr (msg);
839
+ if (zconfig_save (self->config, filename))
840
+ zsys_warning ("cannot save config file '%s'", filename);
841
+ free (filename);
842
+ }
843
+ else {
844
+ // Execute custom method
845
+ zmsg_t *reply = server_method (&self->server, method, msg);
846
+ // If reply isn't null, send it to caller
847
+ zmsg_send (&reply, self->pipe);
848
+ }
849
+ free (method);
850
+ zmsg_destroy (&msg);
851
+ return 0;
852
+ }
853
+
854
+ // Handle a protocol message from the client
855
+
856
+ static int
857
+ s_server_handle_protocol (zloop_t *loop, zsock_t *reader, void *argument)
858
+ {
859
+ s_server_t *self = (s_server_t *) argument;
860
+ // We process as many messages as we can, to reduce the overhead
861
+ // of polling and the reactor:
862
+ while (zsock_events (self->router) & ZMQ_POLLIN) {
863
+ if (zgossip_msg_recv (self->message, self->router))
864
+ return -1; // Interrupted; exit zloop
865
+
866
+ // TODO: use binary hashing on routing_id
867
+ char *hashkey = zframe_strhex (zgossip_msg_routing_id (self->message));
868
+ s_client_t *client = (s_client_t *) zhash_lookup (self->clients, hashkey);
869
+ if (client == NULL) {
870
+ client = s_client_new (self, zgossip_msg_routing_id (self->message));
871
+ zhash_insert (self->clients, hashkey, client);
872
+ zhash_freefn (self->clients, hashkey, s_client_free);
873
+ }
874
+ free (hashkey);
875
+ // Any input from client counts as activity
876
+ if (client->ticket)
877
+ zloop_ticket_reset (self->loop, client->ticket);
878
+
879
+ // Pass to client state machine
880
+ s_client_execute (client, s_protocol_event (self->message));
881
+ }
882
+ return 0;
883
+ }
884
+
885
+ // Watch server config file and reload if changed
886
+
887
+ static int
888
+ s_watch_server_config (zloop_t *loop, int timer_id, void *argument)
889
+ {
890
+ s_server_t *self = (s_server_t *) argument;
891
+ if (zconfig_has_changed (self->config)
892
+ && zconfig_reload (&self->config) == 0) {
893
+ s_server_config_service (self);
894
+ self->server.config = self->config;
895
+ zsys_notice ("reloaded configuration from %s",
896
+ zconfig_filename (self->config));
897
+ }
898
+ return 0;
899
+ }
900
+
901
+
902
+ // ---------------------------------------------------------------------------
903
+ // This is the server actor, which polls its two sockets and processes
904
+ // incoming messages
905
+
906
+ void
907
+ zgossip (zsock_t *pipe, void *args)
908
+ {
909
+ // Initialize
910
+ s_server_t *self = s_server_new (pipe);
911
+ assert (self);
912
+ zsock_signal (pipe, 0);
913
+ // Actor argument may be a string used for logging
914
+ self->log_prefix = args? (char *) args: "";
915
+
916
+ // Set-up server monitor to watch for config file changes
917
+ engine_set_monitor ((server_t *) self, 1000, s_watch_server_config);
918
+ // Set up handler for the two main sockets the server uses
919
+ engine_handle_socket ((server_t *) self, self->pipe, s_server_handle_pipe);
920
+ engine_handle_socket ((server_t *) self, self->router, s_server_handle_protocol);
921
+
922
+ // Run reactor until there's a termination signal
923
+ zloop_start (self->loop);
924
+
925
+ // Reactor has ended
926
+ s_server_destroy (&self);
927
+ }