static void idle_add_keepalive_timeout(struct cmd_idle_context *ctx) { unsigned int interval = ctx->client->set->imap_idle_notify_interval; unsigned int client_hash; if (interval == 0) return; /* set the interval so that the client gets the keepalive notifications at exactly the same time for all the connections. this helps to reduce battery usage in mobile devices. but we don't really want to send this notification for everyone at the same time, because it would cause huge peaks of activity. basing the notifications on the username works well for one account, but basing it on the IP address allows the client to get all of the notifications at the same time for multiple accounts as well (of course assuming Dovecot is running on all the servers :) one potential downside to using IP is that if a proxy hides the client's IP address notifications are sent to everyone at the same time, but this can be avoided by using a properly configured Dovecot proxy. we'll also try to avoid this by not doing it for the commonly used intranet IP ranges. */ client_hash = ctx->client->user->remote_ip != NULL && remote_ip_is_usable(ctx->client->user->remote_ip) ? net_ip_hash(ctx->client->user->remote_ip) : crc32_str(ctx->client->user->username); interval -= (time(NULL) + client_hash) % interval; if (ctx->keepalive_to != NULL) timeout_remove(&ctx->keepalive_to); ctx->keepalive_to = timeout_add(interval * 1000, keepalive_timeout, ctx); }
void test_crc32(void) { const char str[] = "foo\0bar"; test_begin("crc32"); test_assert(crc32_str(str) == 0x8c736521); test_assert(crc32_data(str, sizeof(str)) == 0x32c9723d); test_end(); }
unsigned int imap_keepalive_interval_msecs(const char *username, const struct ip_addr *ip, unsigned int interval_secs) { unsigned int client_hash; client_hash = ip != NULL && imap_remote_ip_is_usable(ip) ? net_ip_hash(ip) : crc32_str(username); interval_secs -= (time(NULL) + client_hash) % interval_secs; return interval_secs * 1000; }