// Execute state machine as long as we have events static void server_client_execute (server_t *self, client_t *client, int event) { client->next_event = event; while (client->next_event) { client->event = client->next_event; client->next_event = 0; switch (client->state) { case start_state: if (client->event == ohai_event) { try_anonymous_access (self, client); client->state = checking_client_state; } else if (client->event == heartbeat_event) { } else if (client->event == expired_event) { terminate_the_client (self, client); } else { // Process all other events fmq_msg_set_id (client->reply, FMQ_MSG_RTFM); fmq_msg_send (&client->reply, client->router); client->reply = fmq_msg_new (0); fmq_msg_set_address (client->reply, client->address); terminate_the_client (self, client); } break; case checking_client_state: if (client->event == friend_event) { fmq_msg_set_id (client->reply, FMQ_MSG_OHAI_OK); fmq_msg_send (&client->reply, client->router); client->reply = fmq_msg_new (0); fmq_msg_set_address (client->reply, client->address); client->state = ready_state; } else if (client->event == foe_event) { fmq_msg_set_id (client->reply, FMQ_MSG_SRSLY); fmq_msg_send (&client->reply, client->router); client->reply = fmq_msg_new (0); fmq_msg_set_address (client->reply, client->address); terminate_the_client (self, client); } else if (client->event == maybe_event) { list_security_mechanisms (self, client); fmq_msg_set_id (client->reply, FMQ_MSG_ORLY); fmq_msg_send (&client->reply, client->router); client->reply = fmq_msg_new (0); fmq_msg_set_address (client->reply, client->address); client->state = challenging_client_state; } else if (client->event == heartbeat_event) { } else if (client->event == expired_event) { terminate_the_client (self, client); } else if (client->event == ohai_event) { try_anonymous_access (self, client); client->state = checking_client_state; } else { // Process all other events fmq_msg_set_id (client->reply, FMQ_MSG_RTFM); fmq_msg_send (&client->reply, client->router); client->reply = fmq_msg_new (0); fmq_msg_set_address (client->reply, client->address); terminate_the_client (self, client); } break; case challenging_client_state: if (client->event == yarly_event) { try_security_mechanism (self, client); client->state = checking_client_state; } else if (client->event == heartbeat_event) { } else if (client->event == expired_event) { terminate_the_client (self, client); } else if (client->event == ohai_event) { try_anonymous_access (self, client); client->state = checking_client_state; } else { // Process all other events fmq_msg_set_id (client->reply, FMQ_MSG_RTFM); fmq_msg_send (&client->reply, client->router); client->reply = fmq_msg_new (0); fmq_msg_set_address (client->reply, client->address); terminate_the_client (self, client); } break; case ready_state: if (client->event == icanhaz_event) { store_client_subscription (self, client); fmq_msg_set_id (client->reply, FMQ_MSG_ICANHAZ_OK); fmq_msg_send (&client->reply, client->router); client->reply = fmq_msg_new (0); fmq_msg_set_address (client->reply, client->address); } else if (client->event == nom_event) { store_client_credit (self, client); get_next_patch_for_client (self, client); client->state = dispatching_state; } else if (client->event == hugz_event) { fmq_msg_set_id (client->reply, FMQ_MSG_HUGZ_OK); fmq_msg_send (&client->reply, client->router); client->reply = fmq_msg_new (0); fmq_msg_set_address (client->reply, client->address); } else if (client->event == kthxbai_event) { terminate_the_client (self, client); } else if (client->event == dispatch_event) { get_next_patch_for_client (self, client); client->state = dispatching_state; } else if (client->event == heartbeat_event) { fmq_msg_set_id (client->reply, FMQ_MSG_HUGZ); fmq_msg_send (&client->reply, client->router); client->reply = fmq_msg_new (0); fmq_msg_set_address (client->reply, client->address); } else if (client->event == expired_event) { terminate_the_client (self, client); } else if (client->event == ohai_event) { try_anonymous_access (self, client); client->state = checking_client_state; } else { // Process all other events fmq_msg_set_id (client->reply, FMQ_MSG_RTFM); fmq_msg_send (&client->reply, client->router); client->reply = fmq_msg_new (0); fmq_msg_set_address (client->reply, client->address); terminate_the_client (self, client); } break; case dispatching_state: if (client->event == send_chunk_event) { fmq_msg_set_id (client->reply, FMQ_MSG_CHEEZBURGER); fmq_msg_send (&client->reply, client->router); client->reply = fmq_msg_new (0); fmq_msg_set_address (client->reply, client->address); get_next_patch_for_client (self, client); } else if (client->event == send_delete_event) { fmq_msg_set_id (client->reply, FMQ_MSG_CHEEZBURGER); fmq_msg_send (&client->reply, client->router); client->reply = fmq_msg_new (0); fmq_msg_set_address (client->reply, client->address); get_next_patch_for_client (self, client); } else if (client->event == next_patch_event) { get_next_patch_for_client (self, client); } else if (client->event == no_credit_event) { client->state = ready_state; } else if (client->event == finished_event) { client->state = ready_state; } else if (client->event == heartbeat_event) { } else if (client->event == expired_event) { terminate_the_client (self, client); } else if (client->event == ohai_event) { try_anonymous_access (self, client); client->state = checking_client_state; } else { // Process all other events fmq_msg_set_id (client->reply, FMQ_MSG_RTFM); fmq_msg_send (&client->reply, client->router); client->reply = fmq_msg_new (0); fmq_msg_set_address (client->reply, client->address); terminate_the_client (self, client); } break; } if (client->next_event == terminate_event) { // Automatically calls client_destroy zhash_delete (self->clients, client->hashkey); break; } } }
void fmq_msg_test (bool verbose) { printf (" * fmq_msg:"); if (verbose) printf ("\n"); // @selftest // Simple create/destroy test fmq_msg_t *self = fmq_msg_new (); assert (self); fmq_msg_destroy (&self); // Create pair of sockets we can send through // We must bind before connect if we wish to remain compatible with ZeroMQ < v4 zsock_t *output = zsock_new (ZMQ_DEALER); assert (output); int rc = zsock_bind (output, "inproc://selftest-fmq_msg"); assert (rc == 0); zsock_t *input = zsock_new (ZMQ_ROUTER); assert (input); rc = zsock_connect (input, "inproc://selftest-fmq_msg"); assert (rc == 0); // Encode/send/decode and verify each message type int instance; self = fmq_msg_new (); fmq_msg_set_id (self, FMQ_MSG_OHAI); // Send twice fmq_msg_send (self, output); fmq_msg_send (self, output); for (instance = 0; instance < 2; instance++) { fmq_msg_recv (self, input); assert (fmq_msg_routing_id (self)); } fmq_msg_set_id (self, FMQ_MSG_OHAI_OK); // Send twice fmq_msg_send (self, output); fmq_msg_send (self, output); for (instance = 0; instance < 2; instance++) { fmq_msg_recv (self, input); assert (fmq_msg_routing_id (self)); } fmq_msg_set_id (self, FMQ_MSG_ICANHAZ); fmq_msg_set_path (self, "Life is short but Now lasts for ever"); zhash_t *icanhaz_options = zhash_new (); zhash_insert (icanhaz_options, "Name", "Brutus"); fmq_msg_set_options (self, &icanhaz_options); zhash_t *icanhaz_cache = zhash_new (); zhash_insert (icanhaz_cache, "Name", "Brutus"); fmq_msg_set_cache (self, &icanhaz_cache); // Send twice fmq_msg_send (self, output); fmq_msg_send (self, output); for (instance = 0; instance < 2; instance++) { fmq_msg_recv (self, input); assert (fmq_msg_routing_id (self)); assert (streq (fmq_msg_path (self), "Life is short but Now lasts for ever")); zhash_t *options = fmq_msg_get_options (self); assert (zhash_size (options) == 2); assert (streq ((char *) zhash_first (options), "Brutus")); assert (streq ((char *) zhash_cursor (options), "Name")); zhash_destroy (&options); if (instance == 1) zhash_destroy (&icanhaz_options); zhash_t *cache = fmq_msg_get_cache (self); assert (zhash_size (cache) == 2); assert (streq ((char *) zhash_first (cache), "Brutus")); assert (streq ((char *) zhash_cursor (cache), "Name")); zhash_destroy (&cache); if (instance == 1) zhash_destroy (&icanhaz_cache); } fmq_msg_set_id (self, FMQ_MSG_ICANHAZ_OK); // Send twice fmq_msg_send (self, output); fmq_msg_send (self, output); for (instance = 0; instance < 2; instance++) { fmq_msg_recv (self, input); assert (fmq_msg_routing_id (self)); } fmq_msg_set_id (self, FMQ_MSG_NOM); fmq_msg_set_credit (self, 123); fmq_msg_set_sequence (self, 123); // Send twice fmq_msg_send (self, output); fmq_msg_send (self, output); for (instance = 0; instance < 2; instance++) { fmq_msg_recv (self, input); assert (fmq_msg_routing_id (self)); assert (fmq_msg_credit (self) == 123); assert (fmq_msg_sequence (self) == 123); } fmq_msg_set_id (self, FMQ_MSG_CHEEZBURGER); fmq_msg_set_sequence (self, 123); fmq_msg_set_operation (self, 123); fmq_msg_set_filename (self, "Life is short but Now lasts for ever"); fmq_msg_set_offset (self, 123); fmq_msg_set_eof (self, 123); zhash_t *cheezburger_headers = zhash_new (); zhash_insert (cheezburger_headers, "Name", "Brutus"); fmq_msg_set_headers (self, &cheezburger_headers); zchunk_t *cheezburger_chunk = zchunk_new ("Captcha Diem", 12); fmq_msg_set_chunk (self, &cheezburger_chunk); // Send twice fmq_msg_send (self, output); fmq_msg_send (self, output); for (instance = 0; instance < 2; instance++) { fmq_msg_recv (self, input); assert (fmq_msg_routing_id (self)); assert (fmq_msg_sequence (self) == 123); assert (fmq_msg_operation (self) == 123); assert (streq (fmq_msg_filename (self), "Life is short but Now lasts for ever")); assert (fmq_msg_offset (self) == 123); assert (fmq_msg_eof (self) == 123); zhash_t *headers = fmq_msg_get_headers (self); assert (zhash_size (headers) == 2); assert (streq ((char *) zhash_first (headers), "Brutus")); assert (streq ((char *) zhash_cursor (headers), "Name")); zhash_destroy (&headers); if (instance == 1) zhash_destroy (&cheezburger_headers); assert (memcmp (zchunk_data (fmq_msg_chunk (self)), "Captcha Diem", 12) == 0); if (instance == 1) zchunk_destroy (&cheezburger_chunk); } fmq_msg_set_id (self, FMQ_MSG_HUGZ); // Send twice fmq_msg_send (self, output); fmq_msg_send (self, output); for (instance = 0; instance < 2; instance++) { fmq_msg_recv (self, input); assert (fmq_msg_routing_id (self)); } fmq_msg_set_id (self, FMQ_MSG_HUGZ_OK); // Send twice fmq_msg_send (self, output); fmq_msg_send (self, output); for (instance = 0; instance < 2; instance++) { fmq_msg_recv (self, input); assert (fmq_msg_routing_id (self)); } fmq_msg_set_id (self, FMQ_MSG_KTHXBAI); // Send twice fmq_msg_send (self, output); fmq_msg_send (self, output); for (instance = 0; instance < 2; instance++) { fmq_msg_recv (self, input); assert (fmq_msg_routing_id (self)); } fmq_msg_set_id (self, FMQ_MSG_SRSLY); fmq_msg_set_reason (self, "Life is short but Now lasts for ever"); // Send twice fmq_msg_send (self, output); fmq_msg_send (self, output); for (instance = 0; instance < 2; instance++) { fmq_msg_recv (self, input); assert (fmq_msg_routing_id (self)); assert (streq (fmq_msg_reason (self), "Life is short but Now lasts for ever")); } fmq_msg_set_id (self, FMQ_MSG_RTFM); fmq_msg_set_reason (self, "Life is short but Now lasts for ever"); // Send twice fmq_msg_send (self, output); fmq_msg_send (self, output); for (instance = 0; instance < 2; instance++) { fmq_msg_recv (self, input); assert (fmq_msg_routing_id (self)); assert (streq (fmq_msg_reason (self), "Life is short but Now lasts for ever")); } fmq_msg_destroy (&self); zsock_destroy (&input); zsock_destroy (&output); // @end printf ("OK\n"); }
int fmq_server_test (bool verbose) { printf (" * fmq_server: "); fflush (stdout); zctx_t *ctx = zctx_new (); fmq_server_t *self; void *dealer = zsocket_new (ctx, ZMQ_DEALER); zsocket_set_rcvtimeo (dealer, 2000); zsocket_connect (dealer, "tcp://localhost:5670"); fmq_msg_t *request, *reply; // Run selftest using '' configuration self = fmq_server_new (); assert (self); int port = fmq_server_bind (self, "tcp://*:5670"); assert (port == 5670); request = fmq_msg_new (FMQ_MSG_OHAI); fmq_msg_send (&request, dealer); reply = fmq_msg_recv (dealer); assert (reply); assert (fmq_msg_id (reply) == FMQ_MSG_SRSLY); fmq_msg_destroy (&reply); request = fmq_msg_new (FMQ_MSG_ICANHAZ); fmq_msg_send (&request, dealer); reply = fmq_msg_recv (dealer); assert (reply); assert (fmq_msg_id (reply) == FMQ_MSG_RTFM); fmq_msg_destroy (&reply); request = fmq_msg_new (FMQ_MSG_NOM); fmq_msg_send (&request, dealer); reply = fmq_msg_recv (dealer); assert (reply); assert (fmq_msg_id (reply) == FMQ_MSG_RTFM); fmq_msg_destroy (&reply); request = fmq_msg_new (FMQ_MSG_HUGZ); fmq_msg_send (&request, dealer); reply = fmq_msg_recv (dealer); assert (reply); assert (fmq_msg_id (reply) == FMQ_MSG_RTFM); fmq_msg_destroy (&reply); fmq_server_destroy (&self); // Run selftest using 'anonymous.cfg' configuration self = fmq_server_new (); assert (self); fmq_server_configure (self, "anonymous.cfg"); port = fmq_server_bind (self, "tcp://*:5670"); assert (port == 5670); request = fmq_msg_new (FMQ_MSG_OHAI); fmq_msg_send (&request, dealer); reply = fmq_msg_recv (dealer); assert (reply); assert (fmq_msg_id (reply) == FMQ_MSG_OHAI_OK); fmq_msg_destroy (&reply); request = fmq_msg_new (FMQ_MSG_NOM); fmq_msg_send (&request, dealer); request = fmq_msg_new (FMQ_MSG_HUGZ); fmq_msg_send (&request, dealer); reply = fmq_msg_recv (dealer); assert (reply); assert (fmq_msg_id (reply) == FMQ_MSG_HUGZ_OK); fmq_msg_destroy (&reply); request = fmq_msg_new (FMQ_MSG_YARLY); fmq_msg_send (&request, dealer); reply = fmq_msg_recv (dealer); assert (reply); assert (fmq_msg_id (reply) == FMQ_MSG_RTFM); fmq_msg_destroy (&reply); fmq_server_destroy (&self); // Run selftest using 'server_test.cfg' configuration self = fmq_server_new (); assert (self); fmq_server_configure (self, "server_test.cfg"); port = fmq_server_bind (self, "tcp://*:5670"); assert (port == 5670); request = fmq_msg_new (FMQ_MSG_OHAI); fmq_msg_send (&request, dealer); reply = fmq_msg_recv (dealer); assert (reply); assert (fmq_msg_id (reply) == FMQ_MSG_ORLY); fmq_msg_destroy (&reply); request = fmq_msg_new (FMQ_MSG_YARLY); fmq_msg_set_mechanism (request, "PLAIN"); fmq_msg_set_response (request, fmq_sasl_plain_encode ("guest", "guest")); fmq_msg_send (&request, dealer); reply = fmq_msg_recv (dealer); assert (reply); assert (fmq_msg_id (reply) == FMQ_MSG_OHAI_OK); fmq_msg_destroy (&reply); request = fmq_msg_new (FMQ_MSG_NOM); fmq_msg_send (&request, dealer); request = fmq_msg_new (FMQ_MSG_HUGZ); fmq_msg_send (&request, dealer); reply = fmq_msg_recv (dealer); assert (reply); assert (fmq_msg_id (reply) == FMQ_MSG_HUGZ_OK); fmq_msg_destroy (&reply); reply = fmq_msg_recv (dealer); assert (reply); assert (fmq_msg_id (reply) == FMQ_MSG_HUGZ); fmq_msg_destroy (&reply); fmq_server_destroy (&self); zctx_destroy (&ctx); // @end // No clean way to wait for a background thread to exit // Under valgrind this will randomly show as leakage // Reduce this by giving server thread time to exit zclock_sleep (200); printf ("OK\n"); return 0; }
static void client_execute (client_t *self, int event) { self->next_event = event; while (self->next_event) { self->event = self->next_event; self->next_event = 0; switch (self->state) { case start_state: if (self->event == ready_event) { fmq_msg_id_set (self->request, FMQ_MSG_OHAI); fmq_msg_send (&self->request, self->dealer); self->request = fmq_msg_new (0); self->state = requesting_access_state; } else if (self->event == srsly_event) { log_access_denied (self); terminate_the_client (self); self->state = start_state; } else if (self->event == rtfm_event) { log_invalid_message (self); terminate_the_client (self); } else { log_protocol_error (self); terminate_the_client (self); } break; case requesting_access_state: if (self->event == orly_event) { try_security_mechanism (self); fmq_msg_id_set (self->request, FMQ_MSG_YARLY); fmq_msg_send (&self->request, self->dealer); self->request = fmq_msg_new (0); self->state = requesting_access_state; } else if (self->event == ohai_ok_event) { connected_to_server (self); get_first_subscription (self); self->state = subscribing_state; } else if (self->event == srsly_event) { log_access_denied (self); terminate_the_client (self); self->state = start_state; } else if (self->event == rtfm_event) { log_invalid_message (self); terminate_the_client (self); } else { log_protocol_error (self); terminate_the_client (self); } break; case subscribing_state: if (self->event == ok_event) { fmq_msg_id_set (self->request, FMQ_MSG_ICANHAZ); fmq_msg_send (&self->request, self->dealer); self->request = fmq_msg_new (0); get_next_subscription (self); self->state = subscribing_state; } else if (self->event == finished_event) { refill_credit_as_needed (self); self->state = ready_state; } else if (self->event == srsly_event) { log_access_denied (self); terminate_the_client (self); self->state = start_state; } else if (self->event == rtfm_event) { log_invalid_message (self); terminate_the_client (self); } else { log_protocol_error (self); terminate_the_client (self); } break; case ready_state: if (self->event == cheezburger_event) { process_the_patch (self); refill_credit_as_needed (self); } else if (self->event == hugz_event) { fmq_msg_id_set (self->request, FMQ_MSG_HUGZ_OK); fmq_msg_send (&self->request, self->dealer); self->request = fmq_msg_new (0); } else if (self->event == subscribe_event) { fmq_msg_id_set (self->request, FMQ_MSG_ICANHAZ); fmq_msg_send (&self->request, self->dealer); self->request = fmq_msg_new (0); } else if (self->event == send_credit_event) { fmq_msg_id_set (self->request, FMQ_MSG_NOM); fmq_msg_send (&self->request, self->dealer); self->request = fmq_msg_new (0); } else if (self->event == icanhaz_ok_event) { } else if (self->event == srsly_event) { log_access_denied (self); terminate_the_client (self); self->state = start_state; } else if (self->event == rtfm_event) { log_invalid_message (self); terminate_the_client (self); } else { log_protocol_error (self); terminate_the_client (self); } break; } if (self->next_event == terminate_event) { self->stopped = true; break; } } }