static long s_tickless (zloop_t *self) { // Calculate tickless timer, up to 1 hour int64_t tickless = zclock_mono () + 1000 * 3600; // Scan timers, which are not sorted // TODO: sort timers properly on insertion s_timer_t *timer = (s_timer_t *) zlistx_first (self->timers); while (timer) { // Find earliest timer if (tickless > timer->when) tickless = timer->when; timer = (s_timer_t *) zlistx_next (self->timers); } // Tickets are sorted, so check first ticket s_ticket_t *ticket = (s_ticket_t *) zlistx_first (self->tickets); if (ticket && tickless > ticket->when) tickless = ticket->when; long timeout = (long) (tickless - zclock_mono ()); if (timeout < 0) timeout = 0; if (self->verbose) zsys_debug ("zloop polling for %d msec", (int) timeout); return timeout * ZMQ_POLL_MSEC; }
void s_service_dispatch (service_t *self) { // for each message, check regexp and dispatch if possible if (zlistx_size (self->offers)) { mlm_msg_t *message = (mlm_msg_t *) zlistx_first (self->queue); while (message) { offer_t *offer = (offer_t *) zlistx_first (self->offers); while (offer) { if (zrex_matches (offer->rex, mlm_msg_subject (message))) { client_t *target = offer->client; assert (target); assert (!target->msg); target->msg = (mlm_msg_t *) zlistx_detach ( self->queue, zlistx_cursor (self->queue)); engine_send_event (target, service_message_event); zlistx_move_end (self->offers, zlistx_cursor (self->offers)); break; } offer = (offer_t *) zlistx_next (self->offers); } message = (mlm_msg_t *) zlistx_next (self->queue); } } }
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); }
void zloop_destroy (zloop_t **self_p) { assert (self_p); if (*self_p) { zloop_t *self = *self_p; // If we never started the loop, yet manipulated timers, we'll have // a zombie list while (zlistx_first (self->zombies)) { // Get timer_id back from pointer int timer_id = (byte *) zlistx_detach (self->zombies, NULL) - (byte *) NULL; s_timer_remove (self, timer_id); } zlistx_destroy (&self->zombies); zlistx_destroy (&self->readers); zlistx_destroy (&self->pollers); zlistx_destroy (&self->timers); zlistx_destroy (&self->tickets); free (self->pollset); free (self->readact); free (self->pollact); free (self); *self_p = NULL; } }
static void deregister_the_client (client_t *self) { // If the client never sent CONNECTION_OPEN then self->address was // never set, so avoid trying to dereference it. Nothing needs to // be cleaned up. if (self->address) { if (*self->address) zsys_info ("client %u address='%s' - de-registering", self->unique_id, 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); }
int zhashx_save (zhashx_t *self, const char *filename) { assert (self); FILE *handle = fopen (filename, "w"); if (!handle) return -1; // Failed to create file if (self->comments) { char *comment = (char *) zlistx_first (self->comments); while (comment) { fprintf (handle, "# %s\n", comment); comment = (char *) zlistx_next (self->comments); } fprintf (handle, "\n"); } uint index; size_t limit = primes [self->prime_index]; for (index = 0; index < limit; index++) { item_t *item = self->items [index]; while (item) { fprintf (handle, "%s=%s\n", (char *) item->key, (char *) item->value); item = item->next; } } fclose (handle); return 0; }
void zloop_poller_end (zloop_t *self, zmq_pollitem_t *item) { assert (self); s_poller_t *poller = (s_poller_t *) zlistx_first (self->pollers); while (poller) { bool match = false; if (item->socket) { if (item->socket == poller->item.socket) match = true; } else { if (item->fd == poller->item.fd) match = true; } if (match) { zlistx_delete (self->pollers, poller->list_handle); // Force rebuild to avoid reading from freed poller self->need_rebuild = true; } poller = (s_poller_t *) zlistx_next (self->pollers); } if (self->verbose) zsys_debug ("zloop: cancel %s poller (%p, %d)", item->socket ? zsys_sockname (zsock_type (item->socket)) : "FD", item->socket, item->fd); }
static void s_ztrie_destroy_children (ztrie_node_t *node) { ztrie_node_t *child = (ztrie_node_t *) zlistx_first (node->children); while (child) { s_ztrie_destroy_children (child); s_ztrie_node_destroy (&child); child = (ztrie_node_t *) zlistx_next (node->children); } }
const char * ziflist_first (ziflist_t *self) { assert (self); interface_t *iface = (interface_t *) zlistx_first ((zlistx_t *) self); if (iface) return iface->name; else return NULL; }
static int s_rebuild_pollset (zloop_t *self) { free (self->pollset); free (self->readact); free (self->pollact); self->pollset = NULL; self->readact = NULL; self->pollact = NULL; self->poll_size = zlistx_size (self->readers) + zlistx_size (self->pollers); self->pollset = (zmq_pollitem_t *) zmalloc (self->poll_size * sizeof (zmq_pollitem_t)); if (!self->pollset) return -1; self->readact = (s_reader_t *) zmalloc (self->poll_size * sizeof (s_reader_t)); if (!self->readact) return -1; self->pollact = (s_poller_t *) zmalloc (self->poll_size * sizeof (s_poller_t)); if (!self->pollact) return -1; s_reader_t *reader = (s_reader_t *) zlistx_first (self->readers); uint item_nbr = 0; while (reader) { zmq_pollitem_t poll_item = { zsock_resolve (reader->sock), 0, ZMQ_POLLIN }; self->pollset [item_nbr] = poll_item; self->readact [item_nbr] = *reader; item_nbr++; reader = (s_reader_t *) zlistx_next (self->readers); } s_poller_t *poller = (s_poller_t *) zlistx_first (self->pollers); while (poller) { self->pollset [item_nbr] = poller->item; self->pollact [item_nbr] = *poller; item_nbr++; poller = (s_poller_t *) zlistx_next (self->pollers); } self->need_rebuild = false; return 0; }
static void s_stream_engine_cancel (stream_engine_t *self, void *client) { selector_t *selector = (selector_t *) zlistx_first (self->selectors); while (selector) { void *handle = zlistx_find (selector->clients, client); if (handle) zlistx_delete (selector->clients, handle); selector = (selector_t *) zlistx_next (self->selectors); } }
static void s_ztrie_print_tree (ztrie_node_t *self) { // Print tree like structure s_ztrie_print_tree_line (self, true); ztrie_node_t *child = (ztrie_node_t *) zlistx_first (self->children); while (child) { s_ztrie_print_tree (child); child = (ztrie_node_t *) zlistx_next (self->children); } }
static struct curl_slist * zlistx_to_slist (zlistx_t *zlist) { struct curl_slist *slist = NULL; char *header = zlistx_first (zlist); while (header) { slist = curl_slist_append(slist, header); header = zlistx_next (zlist); } return slist; }
static ztrie_node_t * s_ztrie_compare_token (ztrie_node_t *parent, char *token, int len) { ztrie_node_t *child = (ztrie_node_t *) zlistx_first (parent->children); while (child) { if (child->token_len == len && strncmp (child->token, token, MIN_LEN (child->token_len, len)) == 0) return child; child = (ztrie_node_t *) zlistx_next (parent->children); } return NULL; }
static void s_timer_remove (zloop_t *self, int timer_id) { s_timer_t *timer = (s_timer_t *) zlistx_first (self->timers); while (timer) { if (timer->timer_id == timer_id) { zlistx_delete (self->timers, timer->list_handle); break; } timer = (s_timer_t *) zlistx_next (self->timers); } }
void ziflist_print (ziflist_t *self) { interface_t *iface; for (iface = (interface_t *) zlistx_first ((zlistx_t *) self); iface != NULL; iface = (interface_t *) zlistx_next ((zlistx_t *) self)) { zsys_info (" - interface name : %s", iface->name); zsys_info (" - interface address : %s", iface->address); zsys_info (" - interface netmask : %s", iface->netmask); zsys_info (" - interface broadcast : %s", iface->broadcast); } }
void zloop_reader_set_tolerant (zloop_t *self, zsock_t *sock) { assert (self); assert (sock); s_reader_t *reader = (s_reader_t *) zlistx_first (self->readers); while (reader) { if (reader->sock == sock) reader->tolerant = true; reader = (s_reader_t *) zlistx_next (self->readers); } }
static int s_stream_engine_handle_message (stream_engine_t *self) { void *sender; mlm_msg_t *msg; zsock_brecv (self->msgpipe, "pp", &sender, &msg); selector_t *selector = (selector_t *) zlistx_first (self->selectors); while (selector) { if (zrex_matches (selector->rex, mlm_msg_subject (msg))) { void *client = zlistx_first (selector->clients); while (client) { if (client != sender) zsock_bsend (self->msgpipe, "pp", client, mlm_msg_link (msg)); client = zlistx_next (selector->clients); } } selector = (selector_t *) zlistx_next (self->selectors); } mlm_msg_unlink (&msg); return 0; }
static void s_stream_engine_compile (stream_engine_t *self, void *client, const char *pattern) { selector_t *selector = (selector_t *) zlistx_first (self->selectors); while (selector) { if (streq (selector->pattern, pattern)) { void *compare = zlistx_first (selector->clients); while (compare) { if (compare == client) break; // Duplicate client, ignore compare = zlistx_next (selector->clients); } // Add client, if it's new if (!compare) zlistx_add_end (selector->clients, client); break; } selector = (selector_t *) zlistx_next (self->selectors); } // Add selector, if it's new if (!selector) zlistx_add_end (self->selectors, s_selector_new (client, pattern)); }
void zloop_reader_end (zloop_t *self, zsock_t *sock) { assert (self); assert (sock); s_reader_t *reader = (s_reader_t *) zlistx_first (self->readers); while (reader) { if (reader->sock == sock) { zlistx_delete (self->readers, reader->list_handle); self->need_rebuild = true; } reader = (s_reader_t *) zlistx_next (self->readers); } if (self->verbose) zsys_debug ("zloop: cancel %s reader", zsock_type_str (sock)); }
static ztrie_node_t * s_ztrie_matches_token (ztrie_node_t *parent, char *token, int len) { char firstbyte = *token; ztrie_node_t *child = (ztrie_node_t *) zlistx_first (parent->children); while (child) { if (child->token_type == NODE_TYPE_STRING) { if (firstbyte == *child->token // This achieves a small performance boost && child->token_len == len && strncmp (child->token, token, MIN_LEN (child->token_len, len)) == 0) return child; } else if (child->token_type == NODE_TYPE_ASTERISK) { child->asterisk_match = strdup (token); return child; } else { // Need to copy token as zrex_matches expects '\0' terminated string char *token_term = s_strndup (token, len); if (zrex_matches (child->regex, token_term)) { if (child->token_type == NODE_TYPE_PARAM) { // One hit means no capturing group was defined // More than one hit indicates that at least on capturing group. // In this case only the values of the capturing groups are considered. if (zrex_hits (child->regex) == 1) s_ztrie_node_update_param (child, 1, zrex_hit (child->regex, 0)); else if (zrex_hits (child->regex) > 1) { int index; for (index = 1; index < zrex_hits (child->regex); index++) s_ztrie_node_update_param (child, index, zrex_hit (child->regex, index)); } } free (token_term); return child; } free (token_term); } child = (ztrie_node_t *) zlistx_next (parent->children); } return NULL; }
static bool s_service_dispatch_message (service_t *self, mlm_msg_t *message) { offer_t *offer = (offer_t *) zlistx_first (self->offers); while (offer) { if (zrex_matches (offer->rex, mlm_msg_subject (message))) { client_t *target = offer->client; assert (target); assert (!target->msg); target->msg = message; engine_send_event (target, service_message_event); zlistx_move_end (self->offers, zlistx_cursor (self->offers)); return true; } offer = (offer_t *) zlistx_next (self->offers); } return false; }
static ztrie_node_t * s_ztrie_node_new (ztrie_node_t *parent, char *token, int token_len, zlistx_t *param_keys, int token_type) { ztrie_node_t *self = (ztrie_node_t *) zmalloc (sizeof (ztrie_node_t)); assert (self); // Initialize properties self->token = s_strndup (token, token_len); self->token_type = token_type; self->token_len = token_len; self->endpoint = false; self->parameter_count = 0; self->parameter_names = NULL; self->parameter_values = NULL; if (param_keys && zlistx_size (param_keys) > 0) { self->parameter_count = zlistx_size (param_keys); self->parameter_names = (char **) malloc (sizeof (char *) * self->parameter_count); self->parameter_values = (char **) malloc (sizeof (char *) * self->parameter_count); char *key = (char *) zlistx_first (param_keys); int index; for (index = 0; index < zlistx_size (param_keys); index++) { self->parameter_names [index] = key; self->parameter_values [index] = NULL; key = (char *) zlistx_next (param_keys); } } if (self->token_type == NODE_TYPE_REGEX || self->token_type == NODE_TYPE_PARAM) self->regex = zrex_new (self->token); self->data = NULL; // Initialize relationships self->parent = parent; if (self->parent) { zlistx_add_end (self->parent->children, self); // Sort regexes to the end to avoid conlficts zlistx_sort (self->parent->children); } size_t parent_path_len = self->parent? self->parent->path_len: 0; self->path_len = parent_path_len + strlen (self->token) + 1; // +1 path delimiter self->children = zlistx_new (); zlistx_set_comparator (self->children, s_ztrie_node_compare); return self; }
static void twps_destroy(twps_server_t **self_p) { assert(self_p); if (*self_p) { twps_server_t *self = *self_p; if (self->verbose) { zsys_info("twps server: shutdowning application server"); } zactor_t *t_printer = zlistx_first(self->ticket_printers); while (t_printer != NULL) { zactor_destroy(&t_printer); t_printer = zlistx_next(self->ticket_printers); } zlistx_destroy(&self->ticket_printers); zsock_destroy(&self->printer_store_sub); zactor_destroy(&self->ticket_store); zactor_destroy(&self->printer_store); zactor_destroy(&self->client_proxy); free(self); *self_p = NULL; } }
void zloop_poller_set_tolerant (zloop_t *self, zmq_pollitem_t *item) { assert (self); // Find matching poller(s) and mark as tolerant s_poller_t *poller = (s_poller_t *) zlistx_first (self->pollers); while (poller) { bool match = false; if (item->socket) { if (item->socket == poller->item.socket) match = true; } else { if (item->fd == poller->item.fd) match = true; } if (match) poller->tolerant = true; poller = (s_poller_t *) zlistx_next (self->pollers); } }
static void server_accept (server_t *self, const char *key, const char *value) { tuple_t *tuple = (tuple_t *) zhashx_lookup (self->tuples, key); if (tuple && streq (tuple->value, value)) return; // Duplicate tuple, do nothing // Create new tuple tuple = (tuple_t *) zmalloc (sizeof (tuple_t)); assert (tuple); tuple->container = self->tuples; tuple->key = strdup (key); tuple->value = strdup (value); // Store new tuple zhashx_update (tuple->container, key, tuple); zhashx_freefn (tuple->container, key, tuple_free); // Deliver to calling application zstr_sendx (self->pipe, "DELIVER", key, value, NULL); // Hold in server context so we can broadcast to all clients self->cur_tuple = tuple; engine_broadcast_event (self, NULL, forward_event); // Copy new tuple announcement to all remotes zgossip_msg_t *gossip = zgossip_msg_new (); zgossip_msg_set_id (gossip, ZGOSSIP_MSG_PUBLISH); zsock_t *remote = (zsock_t *) zlistx_first (self->remotes); while (remote) { zgossip_msg_set_key (gossip, tuple->key); zgossip_msg_set_value (gossip, tuple->value); zgossip_msg_send (gossip, remote); remote = (zsock_t *) zlistx_next (self->remotes); } zgossip_msg_destroy (&gossip); }
/// // Return the item at the head of list. If the list is empty, returns NULL. // Leaves cursor pointing at the head item, or NULL if the list is empty. void * QZlistx::first () { void * rv = zlistx_first (self); return rv; }
void zcertstore_test (bool verbose) { printf (" * zcertstore: "); if (verbose) printf ("\n"); // @selftest const char *SELFTEST_DIR_RW = "src/selftest-rw"; const char *testbasedir = ".test_zcertstore"; const char *testfile = "mycert.txt"; char *basedirpath = NULL; // subdir in a test, under SELFTEST_DIR_RW char *filepath = NULL; // pathname to testfile in a test, in dirpath basedirpath = zsys_sprintf ("%s/%s", SELFTEST_DIR_RW, testbasedir); assert (basedirpath); filepath = zsys_sprintf ("%s/%s", basedirpath, testfile); assert (filepath); // Make sure old aborted tests do not hinder us zdir_t *dir = zdir_new (basedirpath, NULL); if (dir) { zdir_remove (dir, true); zdir_destroy (&dir); } zsys_file_delete (filepath); zsys_dir_delete (basedirpath); // Create temporary directory for test files zsys_dir_create (basedirpath); // Load certificate store from disk; it will be empty zcertstore_t *certstore = zcertstore_new (basedirpath); assert (certstore); // Create a single new certificate and save to disk zcert_t *cert = zcert_new (); assert (cert); char *client_key = strdup (zcert_public_txt (cert)); assert (client_key); zcert_set_meta (cert, "name", "John Doe"); zcert_save (cert, filepath); zcert_destroy (&cert); // Check that certificate store refreshes as expected cert = zcertstore_lookup (certstore, client_key); assert (cert); assert (streq (zcert_meta (cert, "name"), "John Doe")); #ifdef CZMQ_BUILD_DRAFT_API // DRAFT-API: Security // Iterate through certs zlistx_t *certs = zcertstore_certs(certstore); cert = (zcert_t *) zlistx_first(certs); int cert_count = 0; while (cert) { assert (streq (zcert_meta (cert, "name"), "John Doe")); cert = (zcert_t *) zlistx_next(certs); cert_count++; } assert(cert_count==1); zlistx_destroy(&certs); #endif // Test custom loader test_loader_state *state = (test_loader_state *) zmalloc (sizeof (test_loader_state)); state->index = 0; zcertstore_set_loader (certstore, s_test_loader, s_test_destructor, (void *)state); #if (ZMQ_VERSION_MAJOR >= 4) cert = zcertstore_lookup (certstore, client_key); assert (cert == NULL); cert = zcertstore_lookup (certstore, "abcdefghijklmnopqrstuvwxyzabcdefghijklmn"); assert (cert); #endif freen (client_key); if (verbose) zcertstore_print (certstore); zcertstore_destroy (&certstore); // Delete all test files dir = zdir_new (basedirpath, NULL); assert (dir); zdir_remove (dir, true); zdir_destroy (&dir); zstr_free (&basedirpath); zstr_free (&filepath); #if defined (__WINDOWS__) zsys_shutdown(); #endif // @end printf ("OK\n"); }
void zlistx_test (bool verbose) { printf (" * zlistx: "); // @selftest zlistx_t *list = zlistx_new (); assert (list); assert (zlistx_size (list) == 0); // Test operations on an empty list assert (zlistx_first (list) == NULL); assert (zlistx_last (list) == NULL); assert (zlistx_next (list) == NULL); assert (zlistx_prev (list) == NULL); assert (zlistx_find (list, "hello") == NULL); assert (zlistx_delete (list, NULL) == -1); assert (zlistx_detach (list, NULL) == NULL); assert (zlistx_delete (list, NULL) == -1); assert (zlistx_detach (list, NULL) == NULL); zlistx_purge (list); zlistx_sort (list); // Use item handlers zlistx_set_destructor (list, (zlistx_destructor_fn *) zstr_free); zlistx_set_duplicator (list, (zlistx_duplicator_fn *) strdup); zlistx_set_comparator (list, (zlistx_comparator_fn *) strcmp); // Try simple insert/sort/delete/next assert (zlistx_next (list) == NULL); zlistx_add_end (list, "world"); assert (streq ((char *) zlistx_next (list), "world")); zlistx_add_end (list, "hello"); assert (streq ((char *) zlistx_prev (list), "hello")); zlistx_sort (list); assert (zlistx_size (list) == 2); void *handle = zlistx_find (list, "hello"); char *item1 = (char *) zlistx_item (list); char *item2 = (char *) zlistx_handle_item (handle); assert (item1 == item2); assert (streq (item1, "hello")); zlistx_delete (list, handle); assert (zlistx_size (list) == 1); char *string = (char *) zlistx_detach (list, NULL); assert (streq (string, "world")); free (string); assert (zlistx_size (list) == 0); // Check next/back work // Now populate the list with items zlistx_add_start (list, "five"); zlistx_add_end (list, "six"); zlistx_add_start (list, "four"); zlistx_add_end (list, "seven"); zlistx_add_start (list, "three"); zlistx_add_end (list, "eight"); zlistx_add_start (list, "two"); zlistx_add_end (list, "nine"); zlistx_add_start (list, "one"); zlistx_add_end (list, "ten"); // Test our navigation skills assert (zlistx_size (list) == 10); assert (streq ((char *) zlistx_last (list), "ten")); assert (streq ((char *) zlistx_prev (list), "nine")); assert (streq ((char *) zlistx_prev (list), "eight")); assert (streq ((char *) zlistx_prev (list), "seven")); assert (streq ((char *) zlistx_prev (list), "six")); assert (streq ((char *) zlistx_prev (list), "five")); assert (streq ((char *) zlistx_first (list), "one")); assert (streq ((char *) zlistx_next (list), "two")); assert (streq ((char *) zlistx_next (list), "three")); assert (streq ((char *) zlistx_next (list), "four")); // Sort by alphabetical order zlistx_sort (list); assert (streq ((char *) zlistx_first (list), "eight")); assert (streq ((char *) zlistx_last (list), "two")); // Moving items around handle = zlistx_find (list, "six"); zlistx_move_start (list, handle); assert (streq ((char *) zlistx_first (list), "six")); zlistx_move_end (list, handle); assert (streq ((char *) zlistx_last (list), "six")); zlistx_sort (list); assert (streq ((char *) zlistx_last (list), "two")); // Copying a list zlistx_t *copy = zlistx_dup (list); assert (copy); assert (zlistx_size (copy) == 10); assert (streq ((char *) zlistx_first (copy), "eight")); assert (streq ((char *) zlistx_last (copy), "two")); zlistx_destroy (©); // Delete items while iterating string = (char *) zlistx_first (list); assert (streq (string, "eight")); string = (char *) zlistx_next (list); assert (streq (string, "five")); zlistx_delete (list, zlistx_cursor (list)); string = (char *) zlistx_next (list); assert (streq (string, "four")); zlistx_purge (list); zlistx_destroy (&list); // @end printf ("OK\n"); }
int zloop_start (zloop_t *self) { assert (self); int rc = 0; // Main reactor loop while (!zsys_interrupted) { if (self->need_rebuild) { // If s_rebuild_pollset() fails, break out of the loop and // return its error rc = s_rebuild_pollset (self); if (rc) break; } rc = zmq_poll (self->pollset, (int) self->poll_size, s_tickless (self)); if (rc == -1 || zsys_interrupted) { if (self->verbose) zsys_debug ("zloop: interrupted"); rc = 0; break; // Context has been shut down } // Handle any timers that have now expired int64_t time_now = zclock_mono (); s_timer_t *timer = (s_timer_t *) zlistx_first (self->timers); while (timer) { if (time_now >= timer->when) { if (self->verbose) zsys_debug ("zloop: call timer handler id=%d", timer->timer_id); rc = timer->handler (self, timer->timer_id, timer->arg); if (rc == -1) break; // Timer handler signaled break if (timer->times && --timer->times == 0) zlistx_delete (self->timers, timer->list_handle); else timer->when += timer->delay; } timer = (s_timer_t *) zlistx_next (self->timers); } // Handle any tickets that have now expired s_ticket_t *ticket = (s_ticket_t *) zlistx_first (self->tickets); while (ticket && time_now >= ticket->when) { if (self->verbose) zsys_debug ("zloop: call ticket handler"); rc = ticket->handler (self, 0, ticket->arg); if (rc == -1) break; // Timer handler signaled break zlistx_delete (self->tickets, ticket->list_handle); ticket = (s_ticket_t *) zlistx_next (self->tickets); } // Handle any readers and pollers that are ready size_t item_nbr; for (item_nbr = 0; item_nbr < self->poll_size && rc >= 0; item_nbr++) { s_reader_t *reader = &self->readact [item_nbr]; if (reader->handler) { if ((self->pollset [item_nbr].revents & ZMQ_POLLERR) && !reader->tolerant) { if (self->verbose) zsys_warning ("zloop: can't read %s socket: %s", zsock_type_str (reader->sock), zmq_strerror (zmq_errno ())); // Give handler one chance to handle error, then kill // reader because it'll disrupt the reactor otherwise. if (reader->errors++) { zloop_reader_end (self, reader->sock); self->pollset [item_nbr].revents = 0; } } else reader->errors = 0; // A non-error happened if (self->pollset [item_nbr].revents) { if (self->verbose) zsys_debug ("zloop: call %s socket handler", zsock_type_str (reader->sock)); rc = reader->handler (self, reader->sock, reader->arg); if (rc == -1 || self->need_rebuild) break; } } else { s_poller_t *poller = &self->pollact [item_nbr]; assert (self->pollset [item_nbr].socket == poller->item.socket); if ((self->pollset [item_nbr].revents & ZMQ_POLLERR) && !poller->tolerant) { if (self->verbose) zsys_warning ("zloop: can't poll %s socket (%p, %d): %s", poller->item.socket ? zsys_sockname (zsock_type (poller->item.socket)) : "FD", poller->item.socket, poller->item.fd, zmq_strerror (zmq_errno ())); // Give handler one chance to handle error, then kill // poller because it'll disrupt the reactor otherwise. if (poller->errors++) { zloop_poller_end (self, &poller->item); self->pollset [item_nbr].revents = 0; } } else poller->errors = 0; // A non-error happened if (self->pollset [item_nbr].revents) { if (self->verbose) zsys_debug ("zloop: call %s socket handler (%p, %d)", poller->item.socket ? zsys_sockname (zsock_type (poller->item.socket)) : "FD", poller->item.socket, poller->item.fd); rc = poller->handler (self, &self->pollset [item_nbr], poller->arg); if (rc == -1 || self->need_rebuild) break; } } } // Now handle any timer zombies // This is going to be slow if we have many timers; we might use // a faster lookup on the timer list. while (zlistx_first (self->zombies)) { // Get timer_id back from pointer int timer_id = (byte *) zlistx_detach (self->zombies, NULL) - (byte *) NULL; s_timer_remove (self, timer_id); } if (rc == -1) break; } self->terminated = true; return rc; }