return conn;
}
-static void auth_request_hash_destroy(void *key __attr_unused__, void *value,
- void *context __attr_unused__)
-{
- struct auth_request *auth_request = value;
-
- auth_request->conn = NULL;
-}
-
void auth_client_connection_destroy(struct auth_client_connection *conn)
{
struct auth_client_connection **pos;
static void auth_client_connection_unref(struct auth_client_connection *conn)
{
+ struct hash_iterate_context *iter;
+ void *key, *value;
+
if (--conn->refcount > 0)
return;
- hash_foreach(conn->auth_requests, auth_request_hash_destroy, NULL);
+ iter = hash_iterate_init(conn->auth_requests);
+ while (hash_iterate(iter, &key, &value)) {
+ struct auth_request *auth_request = value;
+
+ auth_request->conn = NULL;
+ }
+ hash_iterate_deinit(iter);
hash_destroy(conn->auth_requests);
i_stream_unref(conn->input);
pool_unref(conn->pool);
}
-static void auth_request_hash_timeout_check(void *key __attr_unused__,
- void *value, void *context)
+static void
+auth_client_connection_check_timeouts(struct auth_client_connection *conn)
{
- struct auth_client_connection *conn = context;
- struct auth_request *auth_request = value;
-
- if (auth_request->created + AUTH_REQUEST_TIMEOUT < ioloop_time) {
- i_warning("Login process has too old (%us) requests, "
- "killing it.",
- (unsigned int)(ioloop_time - auth_request->created));
+ struct hash_iterate_context *iter;
+ void *key, *value;
+ unsigned int secs;
+ int destroy = FALSE;
+
+ iter = hash_iterate_init(conn->auth_requests);
+ while (hash_iterate(iter, &key, &value)) {
+ struct auth_request *auth_request = value;
+
+ if (auth_request->created + AUTH_REQUEST_TIMEOUT < ioloop_time) {
+ secs = (unsigned int) (ioloop_time -
+ auth_request->created);
+ i_warning("Login process has too old (%us) requests, "
+ "killing it.", secs);
+
+ destroy = TRUE;
+ break;
+ }
+ }
+ hash_iterate_deinit(iter);
+ if (destroy)
auth_client_connection_destroy(conn);
- hash_foreach_stop();
- }
}
static void request_timeout(void *context __attr_unused__)
for (conn = master->clients; conn != NULL; conn = next) {
next = conn->next;
-
- conn->refcount++;
- hash_foreach(conn->auth_requests,
- auth_request_hash_timeout_check, conn);
- auth_client_connection_unref(conn);
+ auth_client_connection_check_timeouts(conn);
}
}
return TRUE;
}
-static void hash_ldap_request_destroy(void *key __attr_unused__,
- void *value, void *context)
+static void ldap_conn_close(struct ldap_connection *conn)
{
- struct ldap_request *request = value;
- struct ldap_connection *conn = context;
+ struct hash_iterate_context *iter;
+ void *key, *value;
- request->callback(conn, request, NULL);
- i_free(request);
-}
+ iter = hash_iterate_init(conn->requests);
+ while (hash_iterate(iter, &key, &value)) {
+ struct ldap_request *request = value;
-static void ldap_conn_close(struct ldap_connection *conn)
-{
- hash_foreach(conn->requests, hash_ldap_request_destroy, conn);
+ request->callback(conn, request, NULL);
+ i_free(request);
+ }
+ hash_iterate_deinit(iter);
hash_clear(conn->requests, FALSE);
conn->connected = FALSE;
o_stream_flush(client->output);
}
-static void client_hash_destroy_oldest(void *key, void *value __attr_unused__,
- void *context)
-{
- struct imap_client *client = key;
- struct imap_client *const *destroy_clients;
- buffer_t *destroy_buf = context;
- size_t i, count;
-
- destroy_clients = buffer_get_data(destroy_buf, &count);
- count /= sizeof(struct imap_client *);
-
- for (i = 0; i < count; i++) {
- if (destroy_clients[i]->created > client->created) {
- buffer_insert(destroy_buf,
- i * sizeof(struct imap_client *),
- &client, sizeof(struct imap_client *));
- break;
- }
- }
-}
-
static void client_destroy_oldest(void)
{
- struct imap_client *const *destroy_clients;
- buffer_t *destroy_buf;
- size_t i, count;
+ struct hash_iterate_context *iter;
+ void *key, *value;
+ struct imap_client *destroy_buf[CLIENT_DESTROY_OLDEST_COUNT];
+ int i;
/* find the oldest clients and put them to destroy-buffer */
- destroy_buf = buffer_create_static_hard(pool_datastack_create(),
- sizeof(struct imap_client *) *
- CLIENT_DESTROY_OLDEST_COUNT);
- hash_foreach(clients, client_hash_destroy_oldest, destroy_buf);
+ memset(destroy_buf, 0, sizeof(destroy_buf));
+
+ iter = hash_iterate_init(clients);
+ while (hash_iterate(iter, &key, &value)) {
+ struct imap_client *client = key;
+
+ for (i = 0; i < CLIENT_DESTROY_OLDEST_COUNT; i++) {
+ if (destroy_buf[i] == NULL ||
+ destroy_buf[i]->created > client->created) {
+ /* @UNSAFE */
+ memmove(destroy_buf+i+1, destroy_buf+i,
+ sizeof(destroy_buf) -
+ (i+1) * sizeof(struct imap_client *));
+ destroy_buf[i] = client;
+ break;
+ }
+ }
+ }
+ hash_iterate_deinit(iter);
/* then kill them */
- destroy_clients = buffer_get_data(destroy_buf, &count);
- count /= sizeof(struct imap_client *);
+ for (i = 0; i < CLIENT_DESTROY_OLDEST_COUNT; i++) {
+ if (destroy_buf[i] == NULL)
+ break;
- for (i = 0; i < count; i++) {
- client_destroy(destroy_clients[i],
+ client_destroy(destroy_buf[i],
"Disconnected: Connection queue full");
}
}
i_info("%s [%s]", text, addr);
}
-static void client_hash_check_idle(void *key, void *value __attr_unused__,
- void *context __attr_unused__)
+static void client_check_idle(struct imap_client *client)
{
- struct imap_client *client = key;
-
if (ioloop_time - client->last_input >= CLIENT_LOGIN_IDLE_TIMEOUT) {
client_send_line(client, "* BYE Disconnected for inactivity.");
client_destroy(client, "Disconnected: Inactivity");
static void idle_timeout(void *context __attr_unused__)
{
- hash_foreach(clients, client_hash_check_idle, NULL);
+ struct hash_iterate_context *iter;
+ void *key, *value;
+
+ iter = hash_iterate_init(clients);
+ while (hash_iterate(iter, &key, &value)) {
+ struct imap_client *client = key;
+
+ client_check_idle(client);
+ }
+ hash_iterate_deinit(iter);
}
unsigned int clients_get_count(void)
return hash_size(clients);
}
-static void client_hash_check_io(void *key, void *value __attr_unused__,
- void *context __attr_unused__)
+void clients_notify_auth_connected(void)
{
- struct imap_client *client = key;
+ struct hash_iterate_context *iter;
+ void *key, *value;
+
+ iter = hash_iterate_init(clients);
+ while (hash_iterate(iter, &key, &value)) {
+ struct imap_client *client = key;
- if (client->input_blocked) {
- client->input_blocked = FALSE;
- client_input(client);
+ if (client->input_blocked) {
+ client->input_blocked = FALSE;
+ client_input(client);
+ }
}
+ hash_iterate_deinit(iter);
}
-void clients_notify_auth_connected(void)
+void clients_destroy_all(void)
{
- hash_foreach(clients, client_hash_check_io, NULL);
-}
+ struct hash_iterate_context *iter;
+ void *key, *value;
-static void client_hash_destroy(void *key, void *value __attr_unused__,
- void *context __attr_unused__)
-{
- client_destroy(key, NULL);
-}
+ iter = hash_iterate_init(clients);
+ while (hash_iterate(iter, &key, &value)) {
+ struct imap_client *client = key;
-void clients_destroy_all(void)
-{
- hash_foreach(clients, client_hash_destroy, NULL);
+ client_destroy(client, NULL);
+ }
+ hash_iterate_deinit(iter);
}
void clients_init(void)
(void)o_stream_send(ctx->output, str_data(str), str_len(str));
}
-static void save_root_cb(void *key __attr_unused__, void *value, void *context)
-{
- struct thread_context *ctx = context;
- struct node *node = value;
-
- if (node->parent == NULL)
- add_root(ctx, node);
-}
-
static void mail_thread_finish(struct thread_context *ctx)
{
+ struct hash_iterate_context *iter;
+ void *key, *value;
struct node *node;
/* (2) save root nodes and drop the msgids */
- hash_foreach(ctx->msgid_hash, save_root_cb, ctx);
+ iter = hash_iterate_init(ctx->msgid_hash);
+ while (hash_iterate(iter, &key, &value)) {
+ struct node *node = value;
+
+ if (node->parent == NULL)
+ add_root(ctx, node);
+ }
+ hash_iterate_deinit(iter);
/* drop the memory allocated for message-IDs and msgid_hash,
reuse their memory for base subjects */
return TRUE;
}
-static void uidlist_hash_get_filenames(void *key, void *value, void *context)
-{
- buffer_t *buf = context;
- struct maildir_hash_rec *hash_rec = value;
-
- if (ACTION(hash_rec) == MAILDIR_FILE_ACTION_NEW)
- buffer_append(buf, (const void *) &key, sizeof(const char *));
-}
-
static int maildir_time_cmp(const void *p1, const void *p2)
{
const char *s1 = *((const char **) p1);
static int maildir_full_sync_finish_new_mails(struct maildir_sync_context *ctx)
{
+ struct hash_iterate_context *iter;
+ void *key, *value;
const char *dir, **new_files;
buffer_t *buf;
unsigned int i;
so we should get them to same order as they were created. */
buf = buffer_create_static_hard(ctx->pool,
ctx->new_count * sizeof(const char *));
- hash_foreach(ctx->files, uidlist_hash_get_filenames, buf);
+ iter = hash_iterate_init(ctx->files);
+ while (hash_iterate(iter, &key, &value)) {
+ struct maildir_hash_rec *hash_rec = value;
+
+ if (ACTION(hash_rec) == MAILDIR_FILE_ACTION_NEW) {
+ buffer_append(buf, (const void *) &key,
+ sizeof(const char *));
+ }
+ }
+ hash_iterate_deinit(iter);
i_assert(buffer_get_used_size(buf) ==
ctx->new_count * sizeof(const char *));
return ret;
}
-static void maildir_sync_hash_fix_allocs(void *key, void *value, void *context)
-{
- struct maildir_sync_context *ctx = context;
- struct maildir_hash_rec *hash_rec = value;
-
- switch (ACTION(hash_rec)) {
- case MAILDIR_FILE_ACTION_NONE:
- hash_remove(ctx->files, key);
- break;
- case MAILDIR_FILE_ACTION_EXPUNGE:
- if (hash_rec->action & MAILDIR_FILE_FLAG_ALLOCED) {
- /* we're getting here because our recently
- inserted node is traversed as well */
- break;
- }
-
- hash_rec->action |= MAILDIR_FILE_FLAG_ALLOCED;
- hash_insert(ctx->files, p_strdup(ctx->pool, key), value);
- break;
- default:
- break;
- }
-}
-
static int maildir_full_sync_dir(struct maildir_sync_context *ctx,
int new_dir, DIR *dirp, struct dirent *d)
{
+ struct hash_iterate_context *iter;
+ void *key, *value;
struct maildir_hash_rec *hash_rec;
void *orig_key, *orig_value;
int newflag;
/* records that are left to hash must not have any (filename) pointers
to cache file. So remove none actions, and p_strdup() expunge
actions. */
- hash_foreach(ctx->files, maildir_sync_hash_fix_allocs, ctx);
+ iter = hash_iterate_init(ctx->files);
+ while (hash_iterate(iter, &key, &value)) {
+ struct maildir_hash_rec *hash_rec = value;
+
+ switch (ACTION(hash_rec)) {
+ case MAILDIR_FILE_ACTION_NONE:
+ hash_remove(ctx->files, key);
+ break;
+ case MAILDIR_FILE_ACTION_EXPUNGE:
+ if (hash_rec->action & MAILDIR_FILE_FLAG_ALLOCED) {
+ /* we're getting here because our recently
+ inserted node is traversed as well */
+ break;
+ }
+
+ hash_rec->action |= MAILDIR_FILE_FLAG_ALLOCED;
+ hash_insert(ctx->files,
+ p_strdup(ctx->pool, key), value);
+ break;
+ default:
+ break;
+ }
+ }
+ hash_iterate_deinit(iter);
return TRUE;
}
static int hash_resize(struct hash_table *table, int grow);
-static int foreach_stop;
-
static int direct_cmp(const void *p1, const void *p2)
{
return p1 == p2 ? 0 : 1;
return table->nodes_count;
}
-void hash_foreach(struct hash_table *table, hash_foreach_callback_t *callback,
- void *context)
+struct hash_iterate_context {
+ struct hash_table *table;
+ struct hash_node *next;
+ size_t pos;
+};
+
+struct hash_iterate_context *hash_iterate_init(struct hash_table *table)
{
- struct hash_node *node;
- size_t i;
+ struct hash_iterate_context *ctx;
hash_freeze(table);
- foreach_stop = FALSE;
-
- for (i = 0; i < table->size; i++) {
- node = &table->nodes[i];
+ ctx = i_new(struct hash_iterate_context, 1);
+ ctx->table = table;
+ ctx->next = &table->nodes[0];
+ return ctx;
+}
- do {
- if (node->key != NULL) {
- callback(node->key, node->value, context);
- if (foreach_stop) {
- table->frozen--;
- return;
- }
+static struct hash_node *hash_iterate_next(struct hash_iterate_context *ctx,
+ struct hash_node *node)
+{
+ do {
+ if (node == NULL) {
+ if (++ctx->pos == ctx->table->size) {
+ ctx->pos--;
+ return NULL;
}
+ node = &ctx->table->nodes[ctx->pos];
+ } else {
node = node->next;
- } while (node != NULL);
+ }
+ } while (node->key == NULL);
+
+ return node;
+}
+
+int hash_iterate(struct hash_iterate_context *ctx,
+ void **key_r, void **value_r)
+{
+ struct hash_node *node;
+
+ node = ctx->next;
+ if (node != NULL && node->key == NULL)
+ node = hash_iterate_next(ctx, node);
+ if (node == NULL) {
+ *key_r = *value_r = NULL;
+ return FALSE;
}
+ *key_r = node->key;
+ *value_r = node->value;
- hash_thaw(table);
+ ctx->next = hash_iterate_next(ctx, node);
+ return TRUE;
}
-void hash_foreach_stop(void)
+void hash_iterate_deinit(struct hash_iterate_context *ctx)
{
- foreach_stop = TRUE;
+ hash_thaw(ctx->table);
+ i_free(ctx);
}
void hash_freeze(struct hash_table *table)
typedef unsigned int hash_callback_t(const void *p);
/* Returns 0 if the pointers are equal. */
typedef int hash_cmp_callback_t(const void *p1, const void *p2);
-typedef void hash_foreach_callback_t(void *key, void *value, void *context);
/* Create a new hash table. If initial_size is 0, the default value is used.
If hash_cb or key_compare_cb is NULL, direct hashing/comparing is used.
void hash_remove(struct hash_table *table, const void *key);
size_t hash_size(struct hash_table *table);
-/* Calls the given function for each node in hash table. You may safely
- call hash_*() functions inside your function, but if you add any
- new nodes, they may or may not be called for in this foreach loop. */
-void hash_foreach(struct hash_table *table,
- hash_foreach_callback_t *callback, void *context);
-/* Stop the active hash_foreach() loop */
-void hash_foreach_stop(void);
+/* Iterates through all nodes in hash table. You may safely call hash_*()
+ functions while iterating, but if you add any new nodes, they may or may
+ not be called for in this iteration. */
+struct hash_iterate_context *hash_iterate_init(struct hash_table *table);
+int hash_iterate(struct hash_iterate_context *ctx,
+ void **key_r, void **value_r);
+void hash_iterate_deinit(struct hash_iterate_context *ctx);
/* Hash table isn't resized, and removed nodes aren't removed from
the list while hash table is freezed. Supports nesting. */
ssl_initialized = TRUE;
}
-static void ssl_proxy_destroy_hash(void *key __attr_unused__, void *value,
- void *context __attr_unused__)
-{
- ssl_proxy_destroy(value);
-}
-
void ssl_proxy_deinit(void)
{
+ struct hash_iterate_context *iter;
+ void *key, *value;
+
if (!ssl_initialized)
return;
- hash_foreach(ssl_proxies, ssl_proxy_destroy_hash, NULL);
+ iter = hash_iterate_init(ssl_proxies);
+ while (hash_iterate(iter, &key, &value))
+ ssl_proxy_destroy(value);
+ hash_iterate_deinit(iter);
hash_destroy(ssl_proxies);
gnutls_certificate_free_cred(x509_cred);
ssl_initialized = TRUE;
}
-static void ssl_proxy_destroy_hash(void *key __attr_unused__, void *value,
- void *context __attr_unused__)
-{
- ssl_proxy_unref(value);
-}
-
void ssl_proxy_deinit(void)
{
+ struct hash_iterate_context *iter;
+ void *key, *value;
+
if (!ssl_initialized)
return;
- hash_foreach(ssl_proxies, ssl_proxy_destroy_hash, NULL);
+ iter = hash_iterate_init(ssl_proxies);
+ while (hash_iterate(iter, &key, &value))
+ ssl_proxy_destroy(value);
+ hash_iterate_deinit(iter);
hash_destroy(ssl_proxies);
SSL_CTX_free(ssl_ctx);
return p;
}
-static void request_hash_destroy(void *key __attr_unused__,
- void *value, void *context __attr_unused__)
-{
- auth_master_callback(NULL, NULL, value);
-}
-
static void auth_process_destroy(struct auth_process *p)
{
+ struct hash_iterate_context *iter;
+ void *key, *value;
struct auth_process **pos;
if (!p->initialized && io_loop_is_running(ioloop)) {
}
p->group->process_count--;
- hash_foreach(p->requests, request_hash_destroy, NULL);
+ iter = hash_iterate_init(p->requests);
+ while (hash_iterate(iter, &key, &value))
+ auth_master_callback(NULL, NULL, value);
+ hash_iterate_deinit(iter);
hash_destroy(p->requests);
i_stream_unref(p->input);
p->group->wanted_processes_count = 0;
}
-static void login_hash_destroy(void *key __attr_unused__, void *value,
- void *context __attr_unused__)
-{
- login_process_destroy(value);
-}
-
void login_processes_destroy_all(void)
{
- hash_foreach(processes, login_hash_destroy, NULL);
+ struct hash_iterate_context *iter;
+ void *key, *value;
+
+ iter = hash_iterate_init(processes);
+ while (hash_iterate(iter, &key, &value))
+ login_process_destroy(value);
+ hash_iterate_deinit(iter);
while (login_groups != NULL) {
struct login_group *group = login_groups;
o_stream_flush(client->output);
}
-static void client_hash_destroy_oldest(void *key, void *value __attr_unused__,
- void *context)
-{
- struct pop3_client *client = key;
- struct pop3_client *const *destroy_clients;
- buffer_t *destroy_buf = context;
- size_t i, count;
-
- destroy_clients = buffer_get_data(destroy_buf, &count);
- count /= sizeof(struct pop3_client *);
-
- for (i = 0; i < count; i++) {
- if (destroy_clients[i]->created > client->created) {
- buffer_insert(destroy_buf,
- i * sizeof(struct pop3_client *),
- &client, sizeof(struct pop3_client *));
- break;
- }
- }
-}
-
static void client_destroy_oldest(void)
{
- struct pop3_client *const *destroy_clients;
- buffer_t *destroy_buf;
- size_t i, count;
+ struct hash_iterate_context *iter;
+ void *key, *value;
+ struct pop3_client *destroy_buf[CLIENT_DESTROY_OLDEST_COUNT];
+ int i;
/* find the oldest clients and put them to destroy-buffer */
- destroy_buf = buffer_create_static_hard(pool_datastack_create(),
- sizeof(struct pop3_client *) *
- CLIENT_DESTROY_OLDEST_COUNT);
- hash_foreach(clients, client_hash_destroy_oldest, destroy_buf);
+ memset(destroy_buf, 0, sizeof(destroy_buf));
+
+ iter = hash_iterate_init(clients);
+ while (hash_iterate(iter, &key, &value)) {
+ struct pop3_client *client = key;
+
+ for (i = 0; i < CLIENT_DESTROY_OLDEST_COUNT; i++) {
+ if (destroy_buf[i] == NULL ||
+ destroy_buf[i]->created > client->created) {
+ /* @UNSAFE */
+ memmove(destroy_buf+i+1, destroy_buf+i,
+ sizeof(destroy_buf) -
+ (i+1) * sizeof(struct pop3_client *));
+ destroy_buf[i] = client;
+ break;
+ }
+ }
+ }
+ hash_iterate_deinit(iter);
/* then kill them */
- destroy_clients = buffer_get_data(destroy_buf, &count);
- count /= sizeof(struct pop3_client *);
+ for (i = 0; i < CLIENT_DESTROY_OLDEST_COUNT; i++) {
+ if (destroy_buf[i] == NULL)
+ break;
- for (i = 0; i < count; i++) {
- client_destroy(destroy_clients[i],
+ client_destroy(destroy_buf[i],
"Disconnected: Connection queue full");
}
}
i_info("%s [%s]", text, addr);
}
-static void client_hash_check_idle(void *key, void *value __attr_unused__,
- void *context __attr_unused__)
+static void client_check_idle(struct pop3_client *client)
{
- struct pop3_client *client = key;
-
if (ioloop_time - client->last_input >= CLIENT_LOGIN_IDLE_TIMEOUT)
client_destroy(client, "Disconnected: Inactivity");
}
static void idle_timeout(void *context __attr_unused__)
{
- hash_foreach(clients, client_hash_check_idle, NULL);
+ struct hash_iterate_context *iter;
+ void *key, *value;
+
+ iter = hash_iterate_init(clients);
+ while (hash_iterate(iter, &key, &value)) {
+ struct pop3_client *client = key;
+
+ client_check_idle(client);
+ }
+ hash_iterate_deinit(iter);
}
unsigned int clients_get_count(void)
return hash_size(clients);
}
-static void client_hash_check_io(void *key, void *value __attr_unused__,
- void *context __attr_unused__)
+void clients_notify_auth_connected(void)
{
- struct pop3_client *client = key;
+ struct hash_iterate_context *iter;
+ void *key, *value;
+
+ iter = hash_iterate_init(clients);
+ while (hash_iterate(iter, &key, &value)) {
+ struct pop3_client *client = key;
- if (client->input_blocked) {
- client->input_blocked = FALSE;
- client_input(client);
+ if (client->input_blocked) {
+ client->input_blocked = FALSE;
+ client_input(client);
+ }
}
+ hash_iterate_deinit(iter);
}
-void clients_notify_auth_connected(void)
+void clients_destroy_all(void)
{
- hash_foreach(clients, client_hash_check_io, NULL);
-}
+ struct hash_iterate_context *iter;
+ void *key, *value;
-static void client_hash_destroy(void *key, void *value __attr_unused__,
- void *context __attr_unused__)
-{
- client_destroy(key, NULL);
-}
+ iter = hash_iterate_init(clients);
+ while (hash_iterate(iter, &key, &value)) {
+ struct pop3_client *client = key;
-void clients_destroy_all(void)
-{
- hash_foreach(clients, client_hash_destroy, NULL);
+ client_destroy(client, NULL);
+ }
+ hash_iterate_deinit(iter);
}
void clients_init(void)