static void s_alerts ( zsock_t *pipe, void *args) { const char *name = "ALERT"; mlm_client_t *cl = mlm_client_new (); mlm_client_connect (cl, endpoint, 5000, __PRETTY_FUNCTION__); mlm_client_set_producer (cl, stream); zsock_t *msgpipe = mlm_client_msgpipe (cl); zpoller_t *poller = zpoller_new (pipe, msgpipe, NULL); char *alert_state = strdup ("NEW"); zsock_signal (pipe, 0); while (!zsys_interrupted) { zsock_t *which = zpoller_wait (poller, 1000); if (!which) { mlm_client_sendx (cl, "alert://upsonbattery@ups1", alert_state, NULL); continue; } if (which == pipe) break; //which == msgpipe zmsg_t *msg = mlm_client_recv (cl); if (!streq (mlm_client_command (cl), "MAILBOX DELIVER")) goto msg_destroy; char *alert_name = zmsg_popstr (msg); zstr_free (&alert_state); alert_state = zmsg_popstr (msg); zsys_info ("%s: Alert '%s' new state is '%s'", name, alert_name, alert_state); zstr_free (&alert_name); msg_destroy: zmsg_destroy (&msg); } zstr_free (&alert_state); zpoller_destroy (&poller); mlm_client_destroy (&cl); }
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; }
int main(int argc, char **argv) { if(argc != 2) { fprintf(stderr, "Usage: %s address\n", argv[0]); exit(1); } char *addr = argv[1]; mlm_client_t *agent = mlm_client_new (); // mlm_client_connect () returns -1 on failure if ( mlm_client_connect (agent, addr, 1000, "UI") == -1 ) { zsys_error ("Cannot connect to the endpoint %s", addr); mlm_client_destroy (&agent); return EXIT_FAILURE; } zmsg_t *getmsg = zmsg_new(); zmsg_addstr(getmsg, "GET"); zmsg_addstr(getmsg, "temperature"); // mlm_client_sendfor () returns zero on success if (mlm_client_sendfor (agent, "stats", "temperature", NULL, 0, &getmsg) !=0 ) { zsys_error ("Cannot send the message"); mlm_client_destroy (&agent); return 1; } getmsg = zmsg_new(); zmsg_addstr(getmsg, "GET"); zmsg_addstr(getmsg, "ups.state"); if (mlm_client_sendfor (agent, "stats", "ups.state", NULL, 0, &getmsg) != 0) { zsys_error ("Cannot send the message"); mlm_client_destroy (&agent); return 1; } getmsg = zmsg_new(); zmsg_addstr(getmsg, "GET"); zmsg_addstr(getmsg, "ups.power"); if (mlm_client_sendfor (agent, "stats", "ups.power", NULL, 0, &getmsg) != 0) { zsys_error ("Cannot send the message"); mlm_client_destroy (&agent); return 1; } // need to read replies, waiying for 3 of them int i = 0; while ( !zsys_interrupted && i < 3 ) { zsys_info ("waiting for %d reply message", i); zmsg_t *msg = mlm_client_recv (agent); if ( msg == NULL ) continue; if ( streq (mlm_client_command (agent), "MAILBOX DELIVER") ) { if ( ( strcmp(mlm_client_subject(agent), "temperature") == 0 ) || ( strcmp(mlm_client_subject(agent), "ups.power") == 0 ) || ( strcmp(mlm_client_subject(agent), "ups.temperature") == 0 ) ) { char *key = zmsg_popstr (msg); char *result = zmsg_popstr (msg); zsys_info ("GOT: %s = %s", key , result); i++; } } zmsg_destroy (&msg); } mlm_client_destroy (&agent); return 0; }
// --------------------------------------------------------------------------- // Selftest void mlm_client_test (bool verbose) { printf (" * mlm_client: \n"); // @selftest mlm_client_verbose = verbose; // Start a server to test against, and bind to endpoint zactor_t *server = zactor_new (mlm_server, "mlm_client_test"); if (verbose) zstr_send (server, "VERBOSE"); zstr_sendx (server, "LOAD", "src/mlm_client.cfg", NULL); // Install authenticator to test PLAIN access zactor_t *auth = zactor_new (zauth, NULL); assert (auth); if (verbose) { zstr_sendx (auth, "VERBOSE", NULL); zsock_wait (auth); } zstr_sendx (auth, "PLAIN", "src/passwords.cfg", NULL); zsock_wait (auth); ///// // Test mutual address exchange /** ----------- ---------- | Frontend | -> 1) provide addr, req opp addr -> |\ / | <- 1) Provide addr, Req opp addr | Backend | >Broker< ----------- 2) Receive opp addr <- -> 2) Receive opposite address ---------- 3) Direct connection establishment ----------- ----------- | Frontend | <- Send -> | Backend | ----------- ----------- */ mlm_client_t *frontend = mlm_client_new (); assert(frontend); mlm_client_t *backend = mlm_client_new(); assert(backend); // connect front side to broker printf("connecting frontend to broker\n"); int rc = mlm_client_set_plain_auth (frontend, "writer", "secret"); assert (rc == 0); rc=mlm_client_connect (frontend, "tcp://127.0.0.1:9999", 1000, ""); assert (rc == 0); // connect back side to broker printf("connecting backend to broker\n"); rc = mlm_client_set_plain_auth (backend, "reader", "secret"); assert (rc == 0); rc=mlm_client_connect (backend, "tcp://127.0.0.1:9999", 1000, ""); assert (rc == 0); //before you ever set a service, you should've already called bind in order to facilitate a // connection from the other side. In this way, it's causally correct. // the frontend tells the broker that it is interested in addresses that are on the other side printf("setting frontend service\n"); mlm_client_set_worker(frontend, "backendEndpoints", "SET*"); // the backend tells the broker that it is interested in addresses that are on the other side printf("setting backend service\n"); mlm_client_set_worker(backend, "frontendEndpoints", "SET*"); // the frontend tells the broker what it's address is, fulfilling a need that the backend set; // consequently, the broker sends this to the backend, which has set a service that it is // subscribed to. SET* matches SET printf("sending frontend address SET message\n"); mlm_client_sendforx(frontend, "frontendEndpoints", "SET", "inproc://frontend", NULL); // the backend tells the broker what it's address is, fullfilling a need that the frontend set; // consequently, the broker sends this to the frontend, which has reported a service to the broker // the broker matches SET to SET*. printf("sending backend address SET message\n"); mlm_client_sendforx(backend, "backendEndpoints", "SET", "inproc://backend", NULL); char *set=NULL, *opp_addr=NULL; printf("receiving on backend"); mlm_client_recvx(backend, &set, &opp_addr, NULL); assert(set); assert(opp_addr); // connect backend to frontend here, then clean up zstr_free(&opp_addr); zstr_free(&set); printf("receiving on backend"); mlm_client_recvx(frontend, &set, &opp_addr, NULL); assert(set); assert(opp_addr); // connect frontend to backend here, then clean up zstr_free(&opp_addr); zstr_free(&set); // cleanup mlm_client_destroy(&backend); mlm_client_destroy(&frontend); // End of mutual address exchange tests ///// // Test stream pattern mlm_client_t *writer = mlm_client_new (); assert (writer); rc = mlm_client_set_plain_auth (writer, "writer", "secret"); assert (rc == 0); assert (mlm_client_connected (writer) == false); rc = mlm_client_connect (writer, "tcp://127.0.0.1:9999", 1000, "writer"); assert (rc == 0); assert (mlm_client_connected (writer) == true); mlm_client_t *reader = mlm_client_new (); assert (reader); rc = mlm_client_set_plain_auth (reader, "reader", "secret"); assert (rc == 0); rc = mlm_client_connect (reader, "tcp://127.0.0.1:9999", 1000, ""); assert (rc == 0); mlm_client_set_producer (writer, "weather"); mlm_client_set_consumer (reader, "weather", "temp.*"); 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); char *subject, *content; mlm_client_recvx (reader, &subject, &content, NULL); assert (streq (subject, "temp.moscow")); assert (streq (content, "1")); assert (streq (mlm_client_command (reader), "STREAM DELIVER")); assert (streq (mlm_client_sender (reader), "writer")); zstr_free (&subject); zstr_free (&content); mlm_client_recvx (reader, &subject, &content, NULL); assert (streq (subject, "temp.madrid")); assert (streq (content, "3")); assert (streq (mlm_client_command (reader), "STREAM DELIVER")); assert (streq (mlm_client_subject (reader), "temp.madrid")); assert (streq (mlm_client_sender (reader), "writer")); zstr_free (&subject); zstr_free (&content); mlm_client_recvx (reader, &subject, &content, NULL); assert (streq (subject, "temp.london")); assert (streq (content, "5")); assert (streq (mlm_client_command (reader), "STREAM DELIVER")); assert (streq (mlm_client_sender (reader), "writer")); zstr_free (&subject); zstr_free (&content); mlm_client_destroy (&reader); // Test mailbox pattern reader = mlm_client_new (); assert (reader); rc = mlm_client_set_plain_auth (reader, "reader", "secret"); assert (rc == 0); rc = mlm_client_connect (reader, "tcp://127.0.0.1:9999", 1000, "mailbox"); assert (rc == 0); mlm_client_sendtox (writer, "mailbox", "subject 1", "Message 1", "attachment", NULL); char *attach; mlm_client_recvx (reader, &subject, &content, &attach, NULL); assert (streq (subject, "subject 1")); assert (streq (content, "Message 1")); assert (streq (attach, "attachment")); assert (streq (mlm_client_command (reader), "MAILBOX DELIVER")); assert (streq (mlm_client_subject (reader), "subject 1")); assert (streq (mlm_client_sender (reader), "writer")); zstr_free (&subject); zstr_free (&content); zstr_free (&attach); // Now test that mailbox survives reader disconnect mlm_client_destroy (&reader); mlm_client_sendtox (writer, "mailbox", "subject 2", "Message 2", NULL); mlm_client_sendtox (writer, "mailbox", "subject 3", "Message 3", NULL); reader = mlm_client_new (); assert (reader); rc = mlm_client_set_plain_auth (reader, "reader", "secret"); assert (rc == 0); rc = mlm_client_connect (reader, "tcp://127.0.0.1:9999", 500, "mailbox"); assert (rc == 0); mlm_client_recvx (reader, &subject, &content, &attach, NULL); assert (streq (subject, "subject 2")); assert (streq (content, "Message 2")); assert (streq (mlm_client_command (reader), "MAILBOX DELIVER")); zstr_free (&subject); zstr_free (&content); mlm_client_recvx (reader, &subject, &content, &attach, NULL); assert (streq (subject, "subject 3")); assert (streq (content, "Message 3")); assert (streq (mlm_client_command (reader), "MAILBOX DELIVER")); zstr_free (&subject); zstr_free (&content); // Test service pattern mlm_client_set_worker (reader, "printer", "bw.*"); mlm_client_set_worker (reader, "printer", "color.*"); mlm_client_sendforx (writer, "printer", "bw.A4", "Important contract", NULL); mlm_client_sendforx (writer, "printer", "bw.A5", "Special conditions", NULL); mlm_client_recvx (reader, &subject, &content, NULL); assert (streq (subject, "bw.A4")); assert (streq (content, "Important contract")); assert (streq (mlm_client_command (reader), "SERVICE DELIVER")); assert (streq (mlm_client_sender (reader), "writer")); zstr_free (&subject); zstr_free (&content); mlm_client_recvx (reader, &subject, &content, NULL); assert (streq (subject, "bw.A5")); assert (streq (content, "Special conditions")); assert (streq (mlm_client_command (reader), "SERVICE DELIVER")); assert (streq (mlm_client_sender (reader), "writer")); zstr_free (&subject); zstr_free (&content); // Test that writer shutdown does not cause message loss mlm_client_set_consumer (reader, "weather", "temp.*"); mlm_client_sendx (writer, "temp.brussels", "7", NULL); mlm_client_destroy (&writer); mlm_client_recvx (reader, &subject, &content, NULL); assert (streq (subject, "temp.brussels")); assert (streq (content, "7")); zstr_free (&subject); zstr_free (&content); mlm_client_destroy (&reader); // Test multiple readers and multiple writers mlm_client_t *writer1 = mlm_client_new (); assert (writer1); rc = mlm_client_set_plain_auth (writer1, "writer", "secret"); assert (rc == 0); rc = mlm_client_connect (writer1, "tcp://127.0.0.1:9999", 1000, ""); assert (rc == 0); mlm_client_t *writer2 = mlm_client_new (); assert (writer2); rc = mlm_client_set_plain_auth (writer2, "writer", "secret"); assert (rc == 0); rc = mlm_client_connect (writer2, "tcp://127.0.0.1:9999", 1000, ""); assert (rc == 0); mlm_client_t *reader1 = mlm_client_new (); assert (reader1); rc = mlm_client_set_plain_auth (reader1, "reader", "secret"); assert (rc == 0); rc = mlm_client_connect (reader1, "tcp://127.0.0.1:9999", 1000, ""); assert (rc == 0); mlm_client_t *reader2 = mlm_client_new (); assert (reader2); rc = mlm_client_set_plain_auth (reader2, "reader", "secret"); assert (rc == 0); rc = mlm_client_connect (reader2, "tcp://127.0.0.1:9999", 1000, ""); assert (rc == 0); mlm_client_set_producer (writer1, "weather"); mlm_client_set_producer (writer2, "traffic"); mlm_client_set_consumer (reader1, "weather", "newyork"); mlm_client_set_consumer (reader1, "traffic", "newyork"); mlm_client_set_consumer (reader2, "weather", "newyork"); mlm_client_set_consumer (reader2, "traffic", "newyork"); mlm_client_sendx (writer1, "newyork", "8", NULL); mlm_client_recvx (reader1, &subject, &content, NULL); assert (streq (mlm_client_address (reader1), "weather")); assert (streq (subject, "newyork")); assert (streq (content, "8")); zstr_free (&subject); zstr_free (&content); mlm_client_recvx (reader2, &subject, &content, NULL); assert (streq (mlm_client_address (reader2), "weather")); assert (streq (subject, "newyork")); assert (streq (content, "8")); zstr_free (&subject); zstr_free (&content); mlm_client_sendx (writer2, "newyork", "85", NULL); mlm_client_recvx (reader1, &subject, &content, NULL); assert (streq (mlm_client_address (reader1), "traffic")); assert (streq (subject, "newyork")); assert (streq (content, "85")); zstr_free (&subject); zstr_free (&content); mlm_client_recvx (reader2, &subject, &content, NULL); assert (streq (mlm_client_address (reader2), "traffic")); assert (streq (subject, "newyork")); assert (streq (content, "85")); zstr_free (&subject); zstr_free (&content); mlm_client_destroy (&writer1); mlm_client_destroy (&writer2); mlm_client_destroy (&reader1); mlm_client_destroy (&reader2); // Done, shut down zactor_destroy (&auth); zactor_destroy (&server); // @end printf ("OK\n"); }