static int zyre_node_stop (zyre_node_t *self) { if (self->beacon) { // Stop broadcast/listen beacon beacon_t beacon; beacon.protocol [0] = 'Z'; beacon.protocol [1] = 'R'; beacon.protocol [2] = 'E'; beacon.version = BEACON_VERSION; beacon.port = 0; // Zero means we're stopping zuuid_export (self->uuid, beacon.uuid); zsock_send (self->beacon, "sbi", "PUBLISH", (byte *) &beacon, sizeof (beacon_t), self->interval); zclock_sleep (1); // Allow 1 msec for beacon to go out zpoller_remove (self->poller, self->beacon); zactor_destroy (&self->beacon); } // Stop polling on inbox zpoller_remove (self->poller, self->inbox); zstr_sendm (self->outbox, "STOP"); zstr_sendm (self->outbox, zuuid_str (self->uuid)); zstr_send (self->outbox, self->name); return 0; }
static void write_message_to_mailbox (client_t *self) { mlm_msg_t *msg = mlm_msg_new ( self->address, mlm_proto_address (self->message), mlm_proto_subject (self->message), mlm_proto_tracker (self->message), mlm_proto_timeout (self->message), mlm_proto_get_content (self->message)); // Try to dispatch to client immediately, if it's connected client_t *target = (client_t *) zhashx_lookup ( self->server->clients, mlm_proto_address (self->message)); if (target) { assert (!target->msg); target->msg = msg; engine_send_event (target, mailbox_message_event); } else // Else store in the eponymous mailbox zsock_send (self->server->mailbox, "ssp", "STORE", mlm_proto_address (self->message), msg); }
static void deregister_the_client (client_t *self) { if (*self->address) zsys_info ("client address='%s' - de-registering", self->address); // Cancel all stream subscriptions stream_t *stream = (stream_t *) zlistx_detach (self->readers, NULL); while (stream) { zsock_send (stream->actor, "sp", "CANCEL", self); stream = (stream_t *) zlistx_detach (self->readers, NULL); } // Cancel all service offerings service_t *service = (service_t *) zhashx_first (self->server->services); while (service) { offer_t *offer = (offer_t *) zlistx_first (service->offers); while (offer) { if (offer->client == self) zlistx_delete (service->offers, zlistx_cursor (service->offers)); offer = (offer_t *) zlistx_next (service->offers); } service = (service_t *) zhashx_next (self->server->services); } if (*self->address) zhashx_delete (self->server->clients, self->address); mlm_proto_set_status_code (self->message, MLM_PROTO_SUCCESS); }
static void signal_have_output_indexes_ok (client_t *self) { zsock_send (self->cmdpipe, "s8p", "OUTPUT INDEXES OK", wap_proto_status (self->message), wap_proto_get_o_indexes (self->message)); }
static void signal_have_random_outs_ok (client_t *self) { zsock_send (self->cmdpipe, "s8p", "RANDOM OUTS OK", wap_proto_status (self->message), wap_proto_get_random_outputs (self->message)); }
static zmsg_t * server_method (server_t *self, const char *method, zmsg_t *msg) { if (streq (method, "CLIENTLIST")) { zmsg_t *reply = zmsg_new (); zmsg_addstr (reply, "CLIENTLIST"); void *item = zhashx_first (self->clients); while (item) { zmsg_addstr (reply, (const char *) zhashx_cursor (self->clients)); item = (void *) zhashx_next (self->clients); } return reply; } if (streq (method, "STREAMLIST")) { zmsg_t *reply = zmsg_new(); zmsg_addstr (reply, "STREAMLIST"); stream_t *stream = (stream_t *) zhashx_first (self->streams); while (stream) { zmsg_addstr (reply, stream->name); stream = (stream_t *) zhashx_next (self->streams); } return reply; } if (streq (method, "SLOW_TEST_MODE")) { // selftest: Tell all stream engines to enable SLOW_TEST_MODE stream_t *stream = (stream_t *) zhashx_first (self->streams); while (stream) { zsock_send (stream->actor, "s", method); stream = (stream_t *) zhashx_next (self->streams); } return NULL; } return NULL; }
static void check_for_mailbox_messages (client_t *self) { if (*self->address) { zsock_send (self->server->mailbox, "ss", "QUERY", self->address); // TODO: break into async reply back to server with client // ID number that server can route to correct client, if it // exists... we need some kind of internal async messaging // to cover all different cases // - engine_send_event (client, event, args) // - stream return // - mailbox to client // - service request to client // -> can each client have a DEALER socket? // -> lookup/route on client unique name? // -> server/client path? centralized for process? // -> do we need lookup, or can we use ROUTER sockets? // -> perhaps using ID? // <<general model for internal messaging>> // requirements, route by name, detect lost route? // credit based flow control // can send mlm_msg_t's all over the place zsock_recv (self->server->mailbox, "p", &self->msg); if (self->msg) engine_set_next_event (self, mailbox_message_event); } }
static void signal_have_get_peer_list_ok (client_t *self) { zsock_send (self->cmdpipe, "s8pp", "GET PEER LIST OK", wap_proto_status (self->message), wap_proto_get_white_list (self->message), wap_proto_get_gray_list (self->message)); }
JNIEXPORT jint JNICALL Java_org_zeromq_czmq_Zsock__1_1send (JNIEnv *env, jclass c, jlong self, jstring picture) { char *picture_ = (char *) (*env)->GetStringUTFChars (env, picture, NULL); jint send_ = (jint) zsock_send ((zsock_t *) (intptr_t) self, picture_); (*env)->ReleaseStringUTFChars (env, picture, picture_); return send_; }
static void signal_request (client_t *self) { mdp_worker_msg_t *worker_msg = self->message; zsock_send(self->msgpipe, "sfm", "REQUEST", mdp_worker_msg_address(worker_msg), mdp_worker_msg_body(worker_msg)); }
static void signal_failure (client_t *self) { xrap_traffic_status_code (self->message); zsock_send (self->cmdpipe, "sis", "FAILURE", xrap_traffic_status_code (self->message), xrap_traffic_status_reason (self->message)); }
static int s_on_read_timer (zloop_t *loop, int timer_id, void *arg) { zdir_watch_t *watch = (zdir_watch_t *) arg; void *data; for (data = zhash_first (watch->subs); data != NULL; data = zhash_next (watch->subs)) { zdir_watch_sub_t *sub = (zdir_watch_sub_t *) data; zdir_t *new_dir = zdir_new (zdir_path (sub->dir), NULL); if (!new_dir) { if (watch->verbose) zsys_error ("zdir_watch: Unable to create new zdir for path %s", zdir_path (sub->dir)); continue; } // Determine if anything has changed. zlist_t *diff = zdir_diff (sub->dir, new_dir, ""); // Do memory management before error handling... zdir_destroy (&sub->dir); sub->dir = new_dir; if (!diff) { if (watch->verbose) zsys_error ("zdir_watch: Unable to create diff for path %s", zdir_path (sub->dir)); continue; } if (zlist_size (diff) > 0) { if (watch->verbose) { zdir_patch_t *patch = (zdir_patch_t *) zlist_first (diff); zsys_info ("zdir_watch: Found %d changes in %s:", zlist_size (diff), zdir_path (sub->dir)); while (patch) { zsys_info ("zdir_watch: %s %s", zfile_filename (zdir_patch_file (patch), NULL), zdir_patch_op (patch) == ZDIR_PATCH_CREATE? "created": "deleted"); patch = (zdir_patch_t *) zlist_next (diff); } } if (zsock_send (watch->pipe, "sp", zdir_path (sub->dir), diff) != 0) { if (watch->verbose) zsys_error ("zdir_watch: Unable to send patch list for path %s", zdir_path (sub->dir)); zlist_destroy (&diff); } // Successfully sent `diff` list - now owned by receiver } else { zlist_destroy (&diff); } } return 0; }
static void signal_have_get_mining_status_ok (client_t *self) { zsock_send (self->cmdpipe, "s8188p", "GET MINING STATUS OK", wap_proto_status (self->message), wap_proto_active (self->message), wap_proto_speed (self->message), wap_proto_thread_count (self->message), wap_proto_get_address (self->message)); }
static void server_configuration (server_t *self, zconfig_t *config) { int dummy; mlm_msgq_cfg_configure (self->service_queue_cfg, config); zsock_send (self->mailbox, "sp", "CONFIGURE", config); // Wait for the mailbox to reconfigure itself so that the zconfig object // is not in use after we return zsock_recv (self->mailbox, "i", &dummy); }
static void signal_have_blocks_ok (client_t *self) { zmsg_t *msg = wap_proto_get_block_data (self->message); assert(msg != 0); printf("%p <--\n", (void*)msg); zsock_send (self->cmdpipe, "s888p", "BLOCKS OK", wap_proto_status(self->message), wap_proto_start_height (self->message), wap_proto_curr_height (self->message), msg); }
static zactor_t * s_broker(char *endpoint) { //1. start malamute zactor_t *broker = zactor_new (mlm_server, NULL); assert (broker); zsys_info ("malamute->bind(\"%s\")", endpoint); zsock_send (broker, "ss", "BIND", endpoint); zstr_send (broker, "VERBOSE"); return broker; }
int zhttp_client_post (zhttp_client_t *self, const char *url, zlistx_t *headers, zchunk_t *body, int timeout, zhttp_client_fn handler, void *arg) { #ifdef HAVE_LIBCURL if (timeout == -1) timeout = 0; if (headers && body) return zsock_send (self, "sslcipp", "POST", url, headers, body, timeout, handler, arg); else if (headers && !body) return zsock_send (self, "sslzipp", "POST", url, headers, timeout, handler, arg); else if (!headers && body) return zsock_send (self, "sszcipp", "POST", url, body, timeout, handler, arg); else return zsock_send (self, "sszzipp", "POST", url, timeout, handler, arg); #else return -1; #endif }
static void signal_have_get_block_template_ok (client_t *self) { zsock_send (self->cmdpipe, "s8888pp", "GET BLOCK TEMPLATE OK", wap_proto_status (self->message), wap_proto_reserved_offset (self->message), wap_proto_height (self->message), wap_proto_difficulty (self->message), wap_proto_get_prev_hash (self->message), wap_proto_get_block_template_blob (self->message)); }
void zhttp_client_test (bool verbose) { #if defined(HAVE_LIBCURL) && defined(ZMQ_STREAM) printf (" * zhttp_client: "); zsock_t *server = zsock_new_stream (NULL); int port = zsock_bind (server, "tcp://127.0.0.1:*"); char url[255]; sprintf (url, "http://127.0.0.1:%d", port); // @selftest // Simple create/destroy test zhttp_client_t *self = zhttp_client_new (verbose); assert (self); // Send the get request zlistx_t *headers = zlistx_new (); zlistx_add_end (headers, "Host: zeromq.org"); zhttp_client_get (self, url, headers, NULL); zlistx_destroy (&headers); // Receive request on the server zchunk_t *routing_id; char *request; int rc = zsock_recv (server, "cs", &routing_id, &request); assert (rc == 0); // Send the response char* response = "HTTP/1.1 200 OK\r\nContent-Length: 5\r\n\r\nHello"; zsock_send (server, "cs", routing_id, response); // Receive the response on the http client int code; zchunk_t *data; zhttp_client_recv (self, &code, &data, NULL); assert (zchunk_streq (data, "Hello")); // Sending another request, without being answer // Checking the client ability to stop while request are inprogres zhttp_client_get (self, url, NULL, NULL); zchunk_destroy (&data); zchunk_destroy (&routing_id); zstr_free (&request); zhttp_client_destroy (&self); zsock_destroy (&server); // @end printf ("OK\n"); #endif }
static void cancel_stream_reader (client_t *self) { // Cancel stream subscription stream_t *stream = s_stream_require (self, mlm_proto_stream (self->message)); if (stream) { zsock_send (stream->actor, "sp", "CANCEL", self); stream = (stream_t *) zlistx_detach (self->readers, NULL); } else { engine_set_exception (self, exception_event); zsys_warning ("stream does not exist"); } }
static void store_stream_reader (client_t *self) { stream_t *stream = s_stream_require (self, mlm_proto_stream (self->message)); if (stream) { zlistx_add_end (self->readers, stream); zsock_send (stream->actor, "sps", "COMPILE", self, mlm_proto_pattern (self->message)); mlm_proto_set_status_code (self->message, MLM_PROTO_SUCCESS); } else { engine_set_exception (self, exception_event); zsys_warning ("reader trying to talk to multiple streams"); } }
STATIC mp_uint_t sock_write(mp_obj_t self_in, const void *buf, mp_uint_t size, int *errcode) { socket_obj_t *socket = self_in; if (socket->ctx == -1) { // already closed *errcode = EBADF; return MP_STREAM_ERROR; } ssize_t len = zsock_send(socket->ctx, buf, size, 0); if (len == -1) { *errcode = errno; return MP_STREAM_ERROR; } return len; }
static void signal_have_get_info_ok (client_t *self) { zsock_send (self->cmdpipe, "s88888888888", "GET INFO OK", wap_proto_status (self->message), wap_proto_height (self->message), wap_proto_target_height (self->message), wap_proto_difficulty (self->message), wap_proto_tx_count (self->message), wap_proto_tx_pool_size (self->message), wap_proto_alt_blocks_count (self->message), wap_proto_outgoing_connections_count (self->message), wap_proto_incoming_connections_count (self->message), wap_proto_white_peerlist_size (self->message), wap_proto_grey_peerlist_size (self->message)); }
static int zyre_node_start (zyre_node_t *self) { if (self->beacon_port) { // Start beacon discovery // ------------------------------------------------------------------ assert (!self->beacon); self->beacon = zactor_new (zbeacon, NULL); if (!self->beacon) return 1; // Not possible to start beacon if (self->verbose) zsock_send (self->beacon, "s", "VERBOSE"); } else { // Start gossip discovery // ------------------------------------------------------------------ // If application didn't set an endpoint explicitly, grab ephemeral // port on all available network interfaces. if (!self->endpoint) { const char *iface = zsys_interface (); if (streq (iface, "")) iface = "*"; self->port = zsock_bind (self->inbox, "tcp://%s:*", iface); assert (self->port > 0); // Die on bad interface or port exhaustion char *hostname = zsys_hostname (); self->endpoint = zsys_sprintf ("tcp://%s:%d", hostname, self->port); zstr_free (&hostname); } assert (self->gossip); zstr_sendx (self->gossip, "PUBLISH", zuuid_str (self->uuid), self->endpoint, NULL); // Start polling on zgossip zpoller_add (self->poller, self->gossip); // Start polling on inbox zpoller_add(self->poller, self->inbox); } return 0; }
static void handler (zsock_t *pipe, void *args) { curl_global_init(CURL_GLOBAL_ALL); CURLM *multi = curl_multi_init (); CURLSH *share = curl_share_init (); curl_share_setopt (share, CURLSHOPT_SHARE, CURL_LOCK_DATA_DNS); curl_share_setopt (share, CURLSHOPT_SHARE, CURL_LOCK_DATA_SSL_SESSION); curl_share_setopt (share, CURLSHOPT_SHARE, CURL_LOCK_DATA_CONNECT); long verbose = (*(bool *) args) ? 1L : 0L; long timeout = 30; CURLMcode code; SOCKET pipefd = zsock_fd (pipe); struct curl_waitfd waitfd = {pipefd, CURL_WAIT_POLLIN}; // List to hold pending curl handles, in case we are destroy the client // while request are inprogress zlistx_t *pending_handles = zlistx_new (); zlistx_set_destructor (pending_handles, (zlistx_destructor_fn *) curl_destructor); zsock_signal (pipe, 0); bool terminated = false; while (!terminated) { int events = zsock_events (pipe); if ((events & ZMQ_POLLIN) == 0) { code = curl_multi_wait (multi, &waitfd, 1, 1000, NULL); assert (code == CURLM_OK); } events = zsock_events (pipe); if (events & ZMQ_POLLIN) { char* command = zstr_recv (pipe); if (!command) break; // Interrupted // All actors must handle $TERM in this way if (streq (command, "$TERM")) terminated = true; else if (streq (command, "GET")) { char *url; zlistx_t *headers; void *userp; int rc = zsock_recv (pipe, "slp", &url, &headers, &userp); assert (rc == 0); zchunk_t *data = zchunk_new (NULL, 100); assert (data); struct curl_slist *curl_headers = zlistx_to_slist (headers); CURL *curl = curl_easy_init (); zlistx_add_end (pending_handles, curl); http_request *request = (http_request *) zmalloc (sizeof (http_request)); assert (request); request->userp = userp; request->curl = curl; request->data = data; request->headers = curl_headers; curl_easy_setopt (curl, CURLOPT_SHARE, share); curl_easy_setopt (curl, CURLOPT_TIMEOUT, timeout); curl_easy_setopt (curl, CURLOPT_VERBOSE, verbose); curl_easy_setopt (curl, CURLOPT_HTTPHEADER, curl_headers); curl_easy_setopt (curl, CURLOPT_URL, url); curl_easy_setopt (curl, CURLOPT_WRITEFUNCTION, write_data); curl_easy_setopt (curl, CURLOPT_WRITEDATA, data); curl_easy_setopt (curl, CURLOPT_PRIVATE, request); code = curl_multi_add_handle (multi, curl); assert (code == CURLM_OK); zlistx_destroy (&headers); zstr_free (&url); } else { puts ("E: invalid message to actor"); assert (false); } zstr_free (&command); } int still_running; code = curl_multi_perform (multi, &still_running); assert (code == CURLM_OK); int msgq = 0; struct CURLMsg *msg = curl_multi_info_read(multi, &msgq); while (msg) { if(msg->msg == CURLMSG_DONE) { CURL *curl = msg->easy_handle; http_request *request; curl_easy_getinfo(curl, CURLINFO_PRIVATE, &request); long response_code_long; curl_easy_getinfo (curl, CURLINFO_RESPONSE_CODE, &response_code_long); int response_code = (int)response_code_long; int rc = zsock_send (pipe, "icp", response_code, request->data, request->userp); assert (rc == 0); curl_multi_remove_handle (multi, curl); // Remove curl from the pending handles and delete it void *handle = zlistx_find (pending_handles, curl); assert (handle); rc = zlistx_delete (pending_handles, handle); assert (rc == 0); } msg = curl_multi_info_read(multi, &msgq); } } zlistx_destroy (&pending_handles); curl_share_cleanup (share); curl_multi_cleanup (multi); curl_global_cleanup (); }
static int mrb_actor_pipe_reader(zloop_t* reactor, zsock_t* pipe, void* args) { errno = 0; self_t* self = (self_t*)args; int rc = 0; zmsg_t* msg = zmsg_recv(pipe); if (!msg) return -1; char* command = zmsg_popstr(msg); zsys_debug("command: %s", command); if (streq(command, "$TERM")) { rc = -1; } else if (streq(command, "BIND ROUTER")) { char* endpoint = zmsg_popstr(msg); if (zsock_bind(self->router, "%s", endpoint) >= 0) { const char* boundendpoint = zsock_endpoint(self->router); zyre_set_header(self->discovery, "mrb-actor-v1-router", "%s", boundendpoint); zsock_signal(pipe, 0); zsock_send(pipe, "s", boundendpoint); } else { zsock_signal(pipe, 1); zsock_send(pipe, "i", errno); } zstr_free(&endpoint); } else if (streq(command, "BIND PULL")) { char* endpoint = zmsg_popstr(msg); if (zsock_bind(self->pull, "%s", endpoint) >= 0) { const char* boundendpoint = zsock_endpoint(self->pull); zyre_set_header(self->discovery, "mrb-actor-v1-pull", "%s", boundendpoint); zsock_signal(pipe, 0); zsock_send(pipe, "s", boundendpoint); } else { zsock_signal(pipe, 1); zsock_send(pipe, "i", errno); } zstr_free(&endpoint); } else if (streq(command, "ZYRE SET ENDPOINT")) { char* endpoint = zmsg_popstr(msg); if (zyre_set_endpoint(self->discovery, "%s", endpoint) == -1) { zsock_signal(pipe, 1); } else { zsock_signal(pipe, 0); } zstr_free(&endpoint); } else if (streq(command, "ZYRE GOSSIP BIND")) { char* endpoint = zmsg_popstr(msg); zyre_gossip_bind(self->discovery, "%s", endpoint); zstr_free(&endpoint); } else if (streq(command, "ZYRE GOSSIP CONNECT")) { char* endpoint = zmsg_popstr(msg); zyre_gossip_connect(self->discovery, "%s", endpoint); zstr_free(&endpoint); } else if (streq(command, "ZYRE START")) { if (zyre_start(self->discovery) == -1) { zsock_signal(pipe, 1); } else { zyre_join(self->discovery, "mrb-actor-v1"); zsock_signal(pipe, 0); } } else if (streq(command, "LOAD IREP FILE")) { char* mrb_file = zmsg_popstr(msg); mrb_state* mrb = self->mrb; int ai = mrb_gc_arena_save(mrb); struct mrb_jmpbuf* prev_jmp = mrb->jmp; struct mrb_jmpbuf c_jmp; MRB_TRY(&c_jmp) { mrb->jmp = &c_jmp; FILE* fp = fopen(mrb_file, "rb"); if (!fp) { mrb_sys_fail(mrb, "fopen"); } mrb_load_irep_file(mrb, fp); fclose(fp); if (mrb->exc) { mrb_exc_raise(mrb, mrb_obj_value(mrb->exc)); } zsock_signal(pipe, 0); mrb->jmp = prev_jmp; } MRB_CATCH(&c_jmp) { mrb->jmp = prev_jmp; mrb_print_error(mrb); zsock_signal(pipe, 1); mrb->exc = NULL; } MRB_END_EXC(&c_jmp); mrb_gc_arena_restore(mrb, ai); zstr_free(&mrb_file); }
static void signal_connect_error (client_t *self) { zsock_send(self->cmdpipe, "si", "CONNECT ERROR", 0); }
static void send_final_response (client_t *self) { zmsg_t *body = mdp_client_msg_get_body(self->message); zsock_send(self->msgpipe, "sm", "FINAL", body); }
void zbeacon_test (bool verbose) { printf (" * zbeacon: "); if (verbose) printf ("\n"); // @selftest // Test 1 - two beacons, one speaking, one listening // Create speaker beacon to broadcast our service zactor_t *speaker = zactor_new (zbeacon, NULL); assert (speaker); if (verbose) zstr_sendx (speaker, "VERBOSE", NULL); zsock_send (speaker, "si", "CONFIGURE", 9999); char *hostname = zstr_recv (speaker); if (!*hostname) { printf ("OK (skipping test, no UDP broadcasting)\n"); zactor_destroy (&speaker); free (hostname); return; } free (hostname); // Create listener beacon on port 9999 to lookup service zactor_t *listener = zactor_new (zbeacon, NULL); assert (listener); if (verbose) zstr_sendx (listener, "VERBOSE", NULL); zsock_send (listener, "si", "CONFIGURE", 9999); hostname = zstr_recv (listener); assert (*hostname); free (hostname); // We will broadcast the magic value 0xCAFE byte announcement [2] = { 0xCA, 0xFE }; zsock_send (speaker, "sbi", "PUBLISH", announcement, 2, 100); // We will listen to anything (empty subscription) zsock_send (listener, "sb", "SUBSCRIBE", "", 0); // Wait for at most 1/2 second if there's no broadcasting zsock_set_rcvtimeo (listener, 500); char *ipaddress = zstr_recv (listener); if (ipaddress) { zframe_t *content = zframe_recv (listener); assert (zframe_size (content) == 2); assert (zframe_data (content) [0] == 0xCA); assert (zframe_data (content) [1] == 0xFE); zframe_destroy (&content); zstr_free (&ipaddress); zstr_sendx (speaker, "SILENCE", NULL); } zactor_destroy (&listener); zactor_destroy (&speaker); // Test subscription filter using a 3-node setup zactor_t *node1 = zactor_new (zbeacon, NULL); assert (node1); zsock_send (node1, "si", "CONFIGURE", 5670); hostname = zstr_recv (node1); assert (*hostname); free (hostname); zactor_t *node2 = zactor_new (zbeacon, NULL); assert (node2); zsock_send (node2, "si", "CONFIGURE", 5670); hostname = zstr_recv (node2); assert (*hostname); free (hostname); zactor_t *node3 = zactor_new (zbeacon, NULL); assert (node3); zsock_send (node3, "si", "CONFIGURE", 5670); hostname = zstr_recv (node3); assert (*hostname); free (hostname); zsock_send (node1, "sbi", "PUBLISH", "NODE/1", 6, 250); zsock_send (node2, "sbi", "PUBLISH", "NODE/2", 6, 250); zsock_send (node3, "sbi", "PUBLISH", "RANDOM", 6, 250); zsock_send (node1, "sb", "SUBSCRIBE", "NODE", 4); // Poll on three API sockets at once zpoller_t *poller = zpoller_new (node1, node2, node3, NULL); assert (poller); int64_t stop_at = zclock_mono () + 1000; while (zclock_mono () < stop_at) { long timeout = (long) (stop_at - zclock_mono ()); if (timeout < 0) timeout = 0; void *which = zpoller_wait (poller, timeout * ZMQ_POLL_MSEC); if (which) { assert (which == node1); char *ipaddress, *received; zstr_recvx (node1, &ipaddress, &received, NULL); assert (streq (received, "NODE/2")); zstr_free (&ipaddress); zstr_free (&received); } } zpoller_destroy (&poller); // Stop listening zstr_sendx (node1, "UNSUBSCRIBE", NULL); // Stop all node broadcasts zstr_sendx (node1, "SILENCE", NULL); zstr_sendx (node2, "SILENCE", NULL); zstr_sendx (node3, "SILENCE", NULL); // Destroy the test nodes zactor_destroy (&node1); zactor_destroy (&node2); zactor_destroy (&node3); // @end printf ("OK\n"); }
int main (int argc, char *argv []) { // Let's start a new Malamute broker zactor_t *broker = zactor_new (mlm_server, NULL); // Switch on verbose tracing... this gets a little overwhelming so you // can comment or delete this when you're bored with it: zsock_send (broker, "s", "VERBOSE"); // We control the broker by sending it commands. It's a CZMQ actor, and // we can talk to it using the zsock API (or zstr, or zframe, or zmsg). // To get things started, let's tell the broker to bind to an endpoint: // zsock_send (broker, "ss", "BIND", "tcp://*:12345"); // This is how we configure a server from an external config file, which // is in http://rfc.zeromq.org/spec:4/ZPL format: zstr_sendx (broker, "LOAD", "src/malamute.cfg", NULL); // We can also, or alternatively, set server properties by sending it // SET commands like this (see malamute.cfg for details): zsock_send (broker, "sss", "SET", "server/timeout", "5000"); // For PLAIN authentication, we start a zauth instance. This handles // all client connection requests by checking against a password file zactor_t *auth = zactor_new (zauth, NULL); assert (auth); // We can switch on verbose tracing to debug authentication errors zstr_sendx (auth, "VERBOSE", NULL); zsock_wait (auth); // Now specify the password file; each line says 'username=password' zstr_sendx (auth, "PLAIN", "src/passwords.cfg", NULL); zsock_wait (auth); // The broker is now running. Let's start two clients, one to publish // messages and one to receive them. We're going to test the stream // pattern with some natty wildcard patterns. mlm_client_t *reader = mlm_client_new (); assert (reader); int rc = mlm_client_set_plain_auth (reader, "reader", "secret"); assert (rc == 0); rc = mlm_client_connect (reader, "tcp://127.0.0.1:9999", 1000, "reader"); assert (rc == 0); mlm_client_t *writer = mlm_client_new (); assert (writer); rc = mlm_client_set_plain_auth (writer, "writer", "secret"); assert (rc == 0); rc = mlm_client_connect (writer, "tcp://127.0.0.1:9999", 1000, "writer"); assert (rc == 0); // The writer publishes to the "weather" stream mlm_client_set_producer (writer, "weather"); // The reader consumes temperature messages off the "weather" stream mlm_client_set_consumer (reader, "weather", "temp.*"); // The writer sends a series of messages with various subjects. The // sendx method sends string data to the stream (we send the subject, // then one or more strings): mlm_client_sendx (writer, "temp.moscow", "1", NULL); mlm_client_sendx (writer, "rain.moscow", "2", NULL); mlm_client_sendx (writer, "temp.madrid", "3", NULL); mlm_client_sendx (writer, "rain.madrid", "4", NULL); mlm_client_sendx (writer, "temp.london", "5", NULL); mlm_client_sendx (writer, "rain.london", "6", NULL); // The simplest way to receive a message is via the recvx method, // which stores multipart string data: char *subject, *content; mlm_client_recvx (reader, &subject, &content, NULL); assert (streq (subject, "temp.moscow")); assert (streq (content, "1")); zstr_free (&subject); zstr_free (&content); // The last-received message has other properties: assert (streq (mlm_client_subject (reader), "temp.moscow")); assert (streq (mlm_client_command (reader), "STREAM DELIVER")); assert (streq (mlm_client_sender (reader), "writer")); assert (streq (mlm_client_address (reader), "weather")); // Let's get the other two messages: mlm_client_recvx (reader, &subject, &content, NULL); assert (streq (subject, "temp.madrid")); assert (streq (content, "3")); zstr_free (&subject); zstr_free (&content); mlm_client_recvx (reader, &subject, &content, NULL); assert (streq (subject, "temp.london")); assert (streq (content, "5")); zstr_free (&subject); zstr_free (&content); // Great, it all works. Now to shutdown, we use the destroy method, // which does a proper deconnect handshake internally: mlm_client_destroy (&reader); mlm_client_destroy (&writer); // Finally, shut down the broker by destroying the actor; this does // a proper shutdown so that all memory is freed as you'd expect. zactor_destroy (&broker); zactor_destroy (&auth); return 0; }