bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2014-2018 Dovecot authors, see the included COPYING file */
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen#define IMAP_HIBERNATE_SOCKET_NAME "imap-hibernate"
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen#define IMAP_HIBERNATE_HANDSHAKE "VERSION\timap-hibernate\t1\t0\n"
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainenstatic int imap_hibernate_handshake(int fd, const char *path)
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen } else if ((ret = read(fd, buf, sizeof(buf)-1)) < 0) {
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen if (version_string_verify(buf, "imap-hibernate", 1))
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen i_error("%s sent invalid VERSION handshake: %s", path, buf);
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainenstatic void imap_hibernate_write_cmd(struct client *client, string_t *cmd,
f24edebe360d3effe584a884aa7d119daf3fd371Aki Tuomi tag = client->command_queue == NULL ? NULL : client->command_queue->tag;
8c1199cac76762101a2ca3ae66443b6b0dc28683Stephan Bosch str_append_tabescaped(cmd, user->set->mail_log_prefix);
a326f9da3c18a4ccfb28e72f87161eaf3624eaf2Timo Sirainen str_printfa(cmd, "\tpeer_dev_major=%lu\tpeer_dev_minor=%lu\tpeer_ino=%llu",
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen str_append_tabescaped(cmd, client->session_id);
60670187b0dd0e7f23f99a58feab11b862ad77acStephan Bosch str_printfa(cmd, "\tlip=%s", net_ip2addr(user->conn.local_ip));
60670187b0dd0e7f23f99a58feab11b862ad77acStephan Bosch str_printfa(cmd, "\trip=%s", net_ip2addr(user->conn.remote_ip));
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen unsigned int i;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen for (i = 0; client->userdb_fields[i] != NULL; i++) {
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen str_append_tabescaped(userdb_fields, client->userdb_fields[i]);
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen str_append_tabescaped(cmd, str_c(userdb_fields));
8c1199cac76762101a2ca3ae66443b6b0dc28683Stephan Bosch str_printfa(cmd, "\tuid=%s", dec2str(user->uid));
8c1199cac76762101a2ca3ae66443b6b0dc28683Stephan Bosch str_printfa(cmd, "\tgid=%s", dec2str(user->gid));
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen str_append_tabescaped(cmd, client_stats(client));
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen strcasecmp(client->command_queue->name, "IDLE") == 0)
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainenimap_hibernate_process_send_cmd(int fd_socket, const char *path,
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen if (imap_hibernate_handshake(fd_socket, path) < 0)
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen if ((ret = fd_send(fd_socket, fd_client, str_data(cmd), 1)) < 0) {
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen if ((ret = write_full(fd_socket, str_data(cmd)+1, str_len(cmd)-1)) < 0) {
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainenstatic int imap_hibernate_process_read(int fd, const char *path)
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen if ((ret = read(fd, buf, sizeof(buf)-1)) < 0) {
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen } else if (ret == 0) {
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainenimap_hibernate_process_send(struct client *client,
f818f91a2e6ee003aaa83323acd74008aa1276d9Timo Sirainen const buffer_t *state, int fd_notify, int *fd_r)
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen path = t_strconcat(client->user->set->base_dir,
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen fd = net_connect_unix_with_retries(path, 1000);
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen i_error("net_connect_unix(%s) failed: %m", path);
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen imap_hibernate_write_cmd(client, cmd, state, fd_notify);
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen if (imap_hibernate_process_send_cmd(fd, path, cmd, client->fd_in) < 0 ||
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen if ((ret = fd_send(fd, fd_notify, "\n", 1)) < 0)
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainenbool imap_client_hibernate(struct client **_client)
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen /* we won't try to hibernate stdio clients */
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen if (o_stream_get_buffer_used_size(client->output) > 0) {
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen /* wait until we've sent the pending output to client */
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen state = buffer_create_dynamic(default_pool, 1024);
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen ret = imap_state_export_internal(client, state, &error);
83228b3f9f6ee8c62a61902e0203af9760f7b9b7Timo Sirainen "Couldn't export state: %s (mailbox=%s)", error,
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen } else if (ret == 0 && client->user->mail_debug) {
83228b3f9f6ee8c62a61902e0203af9760f7b9b7Timo Sirainen "Couldn't export state: %s (mailbox=%s)", error,
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen fd_notify = mailbox_watch_extract_notify_fd(client->mailbox,
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen "Couldn't extract notifications fd: %s",
f818f91a2e6ee003aaa83323acd74008aa1276d9Timo Sirainen if (imap_hibernate_process_send(client, state, fd_notify, &fd_hibernate) < 0)
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen /* hide the disconnect log message, because the client didn't
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen actually log out */
f32c6ed9db6f4c535f97a2020401572efc8abf86Timo Sirainen i_debug("Successfully hibernated imap client in mailbox %s",
f818f91a2e6ee003aaa83323acd74008aa1276d9Timo Sirainen /* notify imap-hibernate that we're done by closing the connection.
f818f91a2e6ee003aaa83323acd74008aa1276d9Timo Sirainen do this only after client is destroyed. this way imap-hibernate
f818f91a2e6ee003aaa83323acd74008aa1276d9Timo Sirainen won't try to launch another imap process too early and cause
f818f91a2e6ee003aaa83323acd74008aa1276d9Timo Sirainen problems (like sending duplicate session ID to stats process) */