static void s_pub_metric(mlm_client_t * mlm, const char *key, const char *dev_name) { char topic[100], value[100]; snprintf (topic, 100, "%s.%s", key, dev_name ); zmsg_t *msg = zmsg_new (); zmsg_addstr (msg, dev_name); zmsg_addstr (msg, key); snprintf (value, 100, "%li", random() % 16 + 10 ); zmsg_addstr (msg, value); mlm_client_send (mlm, topic, &msg); printf ("sending %s/%s/%s\n", dev_name, key, value); }
void mlm_server_test (bool verbose) { printf (" * mlm_server: "); if (verbose) printf ("\n"); // @selftest zactor_t *server = zactor_new (mlm_server, "mlm_server_test"); if (verbose) zstr_send (server, "VERBOSE"); zstr_sendx (server, "BIND", "tcp://127.0.0.1:*", NULL); zstr_sendx (server, "PORT", NULL); char *command, *port; int rc = zstr_recvx (server, &command, &port, NULL); assert (rc == 2); assert (streq (command, "PORT")); assert (strlen (port) > 0 && strlen (port) < 6); assert (!streq (port, "-1")); zsock_t *reader = zsock_new (ZMQ_DEALER); assert (reader); zsock_connect (reader, "tcp://127.0.0.1:%s", port); zsock_set_rcvtimeo (reader, 500); mlm_proto_t *proto = mlm_proto_new (); // Server insists that connection starts properly mlm_proto_set_id (proto, MLM_PROTO_STREAM_WRITE); mlm_proto_send (proto, reader); zclock_sleep (500); // to calm things down && make memcheck pass. Thanks @malanka mlm_proto_recv (proto, reader); zclock_sleep (500); // detto as above assert (mlm_proto_id (proto) == MLM_PROTO_ERROR); assert (mlm_proto_status_code (proto) == MLM_PROTO_COMMAND_INVALID); // Now do a stream publish-subscribe test zsock_t *writer = zsock_new (ZMQ_DEALER); assert (writer); zsock_connect (writer, "tcp://127.0.0.1:%s", port); zsock_set_rcvtimeo (reader, 500); // Open connections from both reader and writer mlm_proto_set_id (proto, MLM_PROTO_CONNECTION_OPEN); mlm_proto_send (proto, reader); mlm_proto_recv (proto, reader); assert (mlm_proto_id (proto) == MLM_PROTO_OK); mlm_proto_set_id (proto, MLM_PROTO_CONNECTION_OPEN); mlm_proto_send (proto, writer); mlm_proto_recv (proto, writer); assert (mlm_proto_id (proto) == MLM_PROTO_OK); // Prepare to write and read a "weather" stream mlm_proto_set_id (proto, MLM_PROTO_STREAM_WRITE); mlm_proto_set_stream (proto, "weather"); mlm_proto_send (proto, writer); mlm_proto_recv (proto, writer); assert (mlm_proto_id (proto) == MLM_PROTO_OK); mlm_proto_set_id (proto, MLM_PROTO_STREAM_READ); mlm_proto_set_pattern (proto, "temp.*"); mlm_proto_send (proto, reader); mlm_proto_recv (proto, reader); assert (mlm_proto_id (proto) == MLM_PROTO_OK); // Now send some weather data, with null contents mlm_proto_set_id (proto, MLM_PROTO_STREAM_SEND); mlm_proto_set_subject (proto, "temp.moscow"); mlm_proto_send (proto, writer); mlm_proto_set_subject (proto, "rain.moscow"); mlm_proto_send (proto, writer); mlm_proto_set_subject (proto, "temp.chicago"); mlm_proto_send (proto, writer); mlm_proto_set_subject (proto, "rain.chicago"); mlm_proto_send (proto, writer); mlm_proto_set_subject (proto, "temp.london"); mlm_proto_send (proto, writer); mlm_proto_set_subject (proto, "rain.london"); mlm_proto_send (proto, writer); // We should receive exactly three deliveries, in order mlm_proto_recv (proto, reader); assert (mlm_proto_id (proto) == MLM_PROTO_STREAM_DELIVER); assert (streq (mlm_proto_subject (proto), "temp.moscow")); mlm_proto_recv (proto, reader); assert (mlm_proto_id (proto) == MLM_PROTO_STREAM_DELIVER); assert (streq (mlm_proto_subject (proto), "temp.chicago")); mlm_proto_recv (proto, reader); assert (mlm_proto_id (proto) == MLM_PROTO_STREAM_DELIVER); assert (streq (mlm_proto_subject (proto), "temp.london")); mlm_proto_destroy (&proto); // Finished, we can clean up zsock_destroy (&writer); zsock_destroy (&reader); zactor_destroy (&server); zstr_free (&port); zstr_free (&command); // Test Case: // CLIENTLIST command { const char *endpoint = "inproc://mlm_server_clientlist_test"; zactor_t *server = zactor_new (mlm_server, "mlm_server_clientlist_test"); if (verbose) zstr_send (server, "VERBOSE"); zstr_sendx (server, "BIND", endpoint, NULL); mlm_client_t *client_1 = mlm_client_new (); int rv = mlm_client_connect (client_1, endpoint, 1000, "Karol"); assert (rv >= 0); mlm_client_t *client_2 = mlm_client_new (); rv = mlm_client_connect (client_2, endpoint, 1000, "Tomas"); assert (rv >= 0); mlm_client_t *client_3 = mlm_client_new (); rv = mlm_client_connect (client_3, endpoint, 1000, "Alenka"); assert (rv >= 0); zclock_sleep (500); zstr_sendx (server, "CLIENTLIST", NULL); zmsg_t *message = zmsg_recv (server); assert (message); assert (zmsg_size (message) == 4); char *pop = zmsg_popstr (message); assert (streq (pop, "CLIENTLIST")); zstr_free (&pop); zlistx_t *expected_names = zlistx_new (); assert (expected_names); zlistx_set_destructor (expected_names, (czmq_destructor *) zstr_free); zlistx_set_duplicator (expected_names, (czmq_duplicator *) strdup); zlistx_set_comparator (expected_names, (czmq_comparator *) strcmp); zlistx_add_end (expected_names, (void *) "Karol"); zlistx_add_end (expected_names, (void *) "Tomas"); zlistx_add_end (expected_names, (void *) "Alenka"); pop = zmsg_popstr (message); assert (pop); void *handle = zlistx_find (expected_names, pop); assert (handle); rv = zlistx_delete (expected_names, handle); assert (rv == 0); zstr_free (&pop); pop = zmsg_popstr (message); assert (pop); handle = zlistx_find (expected_names, pop); assert (handle); rv = zlistx_delete (expected_names, handle); assert (rv == 0); zstr_free (&pop); pop = zmsg_popstr (message); assert (pop); handle = zlistx_find (expected_names, pop); assert (handle); rv = zlistx_delete (expected_names, handle); assert (rv == 0); zstr_free (&pop); pop = zmsg_popstr (message); assert (pop == NULL); assert (zlistx_size (expected_names) == 0); zmsg_destroy (&message); // remove a client Karol mlm_client_destroy (&client_1); zlistx_add_end (expected_names, (void *) "Tomas"); zlistx_add_end (expected_names, (void *) "Alenka"); zstr_sendx (server, "CLIENTLIST", NULL); zclock_sleep (100); message = zmsg_recv (server); assert (message); assert (zmsg_size (message) == 3); pop = zmsg_popstr (message); assert (streq (pop, "CLIENTLIST")); zstr_free (&pop); pop = zmsg_popstr (message); assert (pop); handle = zlistx_find (expected_names, pop); assert (handle); rv = zlistx_delete (expected_names, handle); assert (rv == 0); zstr_free (&pop); pop = zmsg_popstr (message); assert (pop); handle = zlistx_find (expected_names, pop); assert (handle); rv = zlistx_delete (expected_names, handle); assert (rv == 0); zstr_free (&pop); pop = zmsg_popstr (message); assert (pop == NULL); assert (zlistx_size (expected_names) == 0); zlistx_destroy (&expected_names); zmsg_destroy (&message); mlm_client_destroy (&client_2); mlm_client_destroy (&client_3); zactor_destroy (&server); } // Test Case: // STREAMLIST command { const char *endpoint = "inproc://mlm_server_streamlist_test"; zactor_t *server = zactor_new (mlm_server, "mlm_server_streamlist_test"); if (verbose) zstr_send (server, "VERBOSE"); zstr_sendx (server, "BIND", endpoint, NULL); mlm_client_t *client_1 = mlm_client_new (); int rv = mlm_client_connect (client_1, endpoint, 1000, "Karol"); assert (rv != -1); rv = mlm_client_set_producer (client_1, "STREAM_1"); assert (rv != -1); mlm_client_t *client_2 = mlm_client_new (); rv = mlm_client_connect (client_2, endpoint, 1000, "Tomas"); assert (rv != -1); rv = mlm_client_set_producer (client_2, "STREAM_2"); assert (rv != -1); mlm_client_t *client_3 = mlm_client_new (); rv = mlm_client_connect (client_3, endpoint, 1000, "Alenka"); assert (rv != -1); rv = mlm_client_set_consumer (client_3, "STREAM_2", ".*"); assert (rv != -1); zclock_sleep (100); zlistx_t *expected_streams = zlistx_new (); assert (expected_streams); zlistx_set_destructor (expected_streams, (czmq_destructor *) zstr_free); zlistx_set_duplicator (expected_streams, (czmq_duplicator *) strdup); zlistx_set_comparator (expected_streams, (czmq_comparator *) strcmp); zlistx_add_end (expected_streams, (void *) "STREAM_1"); zlistx_add_end (expected_streams, (void *) "STREAM_2"); zstr_sendx (server, "STREAMLIST", NULL); zmsg_t *message = zmsg_recv (server); assert (message); assert (zmsg_size (message) == 3); char *pop = zmsg_popstr (message); assert (streq (pop, "STREAMLIST")); zstr_free (&pop); pop = zmsg_popstr (message); assert (pop); void *handle = zlistx_find (expected_streams, pop); assert (handle); rv = zlistx_delete (expected_streams, handle); assert (rv == 0); zstr_free (&pop); pop = zmsg_popstr (message); assert (pop); handle = zlistx_find (expected_streams, pop); assert (handle); rv = zlistx_delete (expected_streams, handle); assert (rv == 0); zstr_free (&pop); pop = zmsg_popstr (message); assert (pop == NULL); assert (zlistx_size (expected_streams) == 0); zmsg_destroy (&message); // NOTE: Currently when producer disconnects, malamute does not destroy the stream // Therefore it doesn't make sense to test removal of streams, but addition mlm_client_t *client_4 = mlm_client_new (); rv = mlm_client_connect (client_4, endpoint, 1000, "Michal"); assert (rv >= 0); rv = mlm_client_set_producer (client_4, "New stream"); assert (rv >= 0); zlistx_add_end (expected_streams, (void *) "STREAM_1"); zlistx_add_end (expected_streams, (void *) "STREAM_2"); zlistx_add_end (expected_streams, (void *) "New stream"); zclock_sleep (100); zstr_sendx (server, "STREAMLIST", NULL); zclock_sleep (100); message = zmsg_recv (server); assert (message); assert (zmsg_size (message) == 4); pop = zmsg_popstr (message); assert (streq (pop, "STREAMLIST")); zstr_free (&pop); pop = zmsg_popstr (message); assert (pop); handle = zlistx_find (expected_streams, pop); assert (handle); rv = zlistx_delete (expected_streams, handle); assert (rv == 0); zstr_free (&pop); pop = zmsg_popstr (message); assert (pop); handle = zlistx_find (expected_streams, pop); assert (handle); rv = zlistx_delete (expected_streams, handle); assert (rv == 0); zstr_free (&pop); pop = zmsg_popstr (message); assert (pop); handle = zlistx_find (expected_streams, pop); assert (handle); rv = zlistx_delete (expected_streams, handle); assert (rv == 0); zstr_free (&pop); pop = zmsg_popstr (message); assert (pop == NULL); assert (zlistx_size (expected_streams) == 0); zlistx_destroy (&expected_streams); zmsg_destroy (&message); mlm_client_destroy (&client_1); mlm_client_destroy (&client_2); mlm_client_destroy (&client_3); mlm_client_destroy (&client_4); zactor_destroy (&server); } // Regression Test Case: // Segfault from deregistering zombie connection { const char *endpoint = "inproc://mlm_server_deregister_zombie_connection_test"; zactor_t *server = zactor_new (mlm_server, "mlm_server_deregister_zombie_connection_test"); if (verbose) zstr_send (server, "VERBOSE"); zstr_sendx (server, "BIND", endpoint, NULL); zstr_sendx (server, "SET", "server/timeout", "3000", NULL); // 3 second client timeout zsock_t *reader = zsock_new (ZMQ_DEALER); assert (reader); zsock_connect (reader, "inproc://mlm_server_deregister_zombie_connection_test"); zsock_set_rcvtimeo (reader, 500); mlm_proto_t *proto = mlm_proto_new (); // If the malamute server is restarted and clients have queued // up ping messages, the'll be sent before any // CONNECTION_OPEN. The server eventually tries to deregister // this and (previously) would derefence a null pointer for // the client address. mlm_proto_set_id (proto, MLM_PROTO_CONNECTION_PING); mlm_proto_send (proto, reader); printf("Regression test for segfault due to leftover client messages after restart...\n"); // Give the server more than 3 seconds to time out the client... zclock_sleep (3100); printf("passed\n"); mlm_proto_destroy (&proto); zsock_destroy (&reader); zactor_destroy (&server); } { const char *endpoint = "inproc://mlm_server_disconnect_pending_stream_traffic"; zactor_t *server = zactor_new (mlm_server, "mlm_server_disconnect_pending_stream_traffic"); if (verbose) { zstr_send (server, "VERBOSE"); printf("Regression test for use-after-free with pending stream traffic after disconnect\n"); } zstr_sendx (server, "BIND", endpoint, NULL); mlm_client_t *producer = mlm_client_new (); assert (mlm_client_connect (producer, endpoint, 1000, "producer") >= 0); assert (mlm_client_set_producer (producer, "STREAM_TEST") >= 0); zstr_sendx (server, "SLOW_TEST_MODE", NULL); mlm_client_t *consumer = mlm_client_new (); assert (mlm_client_connect (consumer, endpoint, 1000, "consumer") >= 0); assert (mlm_client_set_consumer (consumer, "STREAM_TEST", ".*") >= 0); zmsg_t *msg = zmsg_new (); zmsg_addstr (msg, "world"); assert (mlm_client_send (producer, "hello", &msg) >= 0); mlm_client_destroy (&consumer); zclock_sleep (2000); mlm_client_destroy (&producer); zactor_destroy (&server); } // @end printf ("OK\n"); }
int main (int argc, char **argv) { unsigned int count = 0; parse_args(argc, argv); if (!endpoint || !name) { zsys_error("endpoint or name not specified."); usage(); } mlm_client_t *client = mlm_client_new (); assert(client); int rv; rv = mlm_client_connect(client, endpoint, 5000, name); if (rv == -1) { zsys_error("connection failed."); mlm_client_destroy (&client); return -1; } rv = mlm_client_set_producer (client, "stream"); if (rv == -1) { zsys_error("set_producer failed."); mlm_client_destroy (&client); return -2; } zsock_t *pipe = mlm_client_msgpipe (client); if (!pipe) { zsys_error ("mlm_client_msgpipe() failed."); mlm_client_destroy (&client); return -3; } zpoller_t *poller = zpoller_new (pipe, NULL); if (!poller) { zsys_error("zpoller_new() failed."); mlm_client_destroy (&client); return -4; } while ( !zsys_interrupted && ( !num_messages || count < num_messages) ) { zsock_t *which = zpoller_wait (poller, interval); if ( which != NULL ) { // so we have something to receive zmsg_t *recv_msg = mlm_client_recv (client); zmsg_destroy (&recv_msg); } // in any case we are going to send something // zclock_sleep(interval); zmsg_t *msg = zmsg_new(); assert (msg); if ( count % 10 == 0) { zmsg_pushstr (msg, "exit"); } else { zmsg_pushstr (msg, "hello"); } zmsg_print(msg); mlm_client_send (client, "testing message", &msg); zmsg_destroy (&msg); ++count; } mlm_client_destroy(&client); zpoller_destroy(&poller); free(endpoint); free(name); zsys_info ("finished, sent: %u.", count); return 0; }