struct connection conn;
struct imap_client *imap_client;
bool imap_client_created;
+ bool finished;
bool debug;
};
if (!client->imap_client_created)
master_service_client_connection_destroyed(master_service);
+ else if (client->finished)
+ imap_client_create_finish(client->imap_client);
connection_deinit(conn);
i_free(conn);
}
conn->version_received = TRUE;
return 1;
}
+ if (client->finished) {
+ i_error("Received unexpected line: %s", line);
+ return -1;
+ }
if (client->imap_client == NULL) {
char *const *args;
} else if (ret == 0) {
/* still need to read another fd */
i_stream_unix_set_read_fd(conn->input);
- o_stream_send_str(conn->output, "+\n");
- return 1;
} else {
- /* finished - always disconnect the hibernate client
- afterwards */
- o_stream_send_str(conn->output, "+\n");
- imap_client_create_finish(client->imap_client);
- return -1;
+ /* finished - wait for disconnection from imap before finishing.
+ this way the old imap process will have time to destroy
+ itself before we have a chance to create another one. */
+ client->finished = TRUE;
}
+ o_stream_send_str(conn->output, "+\n");
+ return 1;
}
void imap_hibernate_client_create(int fd, bool debug)
static int
imap_hibernate_process_send(struct client *client,
- const buffer_t *state, int fd_notify)
+ const buffer_t *state, int fd_notify, int *fd_r)
{
string_t *cmd = t_str_new(512);
const char *path;
i_assert(state->used > 0);
+ *fd_r = -1;
+
path = t_strconcat(client->user->set->base_dir,
"/"IMAP_HIBERNATE_SOCKET_NAME, NULL);
fd = net_connect_unix_with_retries(path, 1000);
ret = imap_hibernate_process_read(fd, path);
}
alarm(0);
- net_disconnect(fd);
- return ret < 0 ? -1 : 0;
+ if (ret < 0) {
+ net_disconnect(fd);
+ return -1;
+ }
+ *fd_r = fd;
+ return 0;
}
bool imap_client_hibernate(struct client **_client)
struct client *client = *_client;
buffer_t *state;
const char *error;
- int ret, fd_notify = -1;
+ int ret, fd_notify = -1, fd_hibernate = -1;
if (client->fd_in != client->fd_out) {
/* we won't try to hibernate stdio clients */
}
}
if (ret > 0) {
- if (imap_hibernate_process_send(client, state, fd_notify) < 0)
+ if (imap_hibernate_process_send(client, state, fd_notify, &fd_hibernate) < 0)
ret = -1;
}
if (fd_notify != -1)
client_destroy(client, NULL);
*_client = NULL;
}
+ /* notify imap-hibernate that we're done by closing the connection.
+ do this only after client is destroyed. this way imap-hibernate
+ won't try to launch another imap process too early and cause
+ problems (like sending duplicate session ID to stats process) */
+ if (fd_hibernate != -1)
+ net_disconnect(fd_hibernate);
buffer_free(&state);
return ret > 0;
}