imap-master-client.c revision 2bc963ea051ddacefe0fa5e26280e8ef853fd6c6
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync/* Copyright (c) 2014-2015 Dovecot authors, see the included COPYING file */
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync /* input we've already read from the IMAP client. */
10cdf5733351fdcd857d439ca32189e812f18682vboxsync /* output that imap-hibernate was supposed to send to IMAP client,
10cdf5733351fdcd857d439ca32189e812f18682vboxsync but couldn't send it yet. */
10cdf5733351fdcd857d439ca32189e812f18682vboxsync /* IMAP connection state */
10cdf5733351fdcd857d439ca32189e812f18682vboxsyncstatic struct connection_list *master_clients = NULL;
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsyncstatic void imap_master_client_destroy(struct connection *conn)
10cdf5733351fdcd857d439ca32189e812f18682vboxsync struct imap_master_client *client = (struct imap_master_client *)conn;
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync master_service_client_connection_destroyed(master_service);
10cdf5733351fdcd857d439ca32189e812f18682vboxsyncimap_master_client_parse_input(const char *const *args, pool_t pool,
10cdf5733351fdcd857d439ca32189e812f18682vboxsync const char **error_r)
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync unsigned int peer_dev_major = 0, peer_dev_minor = 0;
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync memset(master_input_r, 0, sizeof(*master_input_r));
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync master_input_r->client_input = buffer_create_dynamic(pool, 64);
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync master_input_r->client_output = buffer_create_dynamic(pool, 16);
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync master_input_r->state = buffer_create_dynamic(pool, 512);
10cdf5733351fdcd857d439ca32189e812f18682vboxsync /* we never want to do userdb lookup again when restoring the client.
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync we have the userdb_fields cached already. */
10cdf5733351fdcd857d439ca32189e812f18682vboxsync input_r->flags_override_remove = MAIL_STORAGE_SERVICE_FLAG_USERDB_LOOKUP;
86abc60770f825f8c2ed4257675b50a08743b687vboxsync if (str_to_ino(value, &master_input_r->peer_ino) < 0) {
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsyncstatic int imap_master_client_verify(const struct imap_master_input *master_input,
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync /* make sure we have the right fd */
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync *error_r = t_strdup_printf("fstat(peer) failed: %m");
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync !CMP_DEV_T(peer_st.st_dev, master_input->peer_dev)) {
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync "BUG: Expected peer device=%u,%u inode=%s doesn't match "
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync "client fd's actual device=%u,%u inode=%s",
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync major(peer_st.st_dev), minor(peer_st.st_dev), dec2str(peer_st.st_ino),
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsyncimap_master_client_input_args(struct connection *conn, const char *const *args,
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync struct imap_master_client *client = (struct imap_master_client *)conn;
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync const char *error;
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync if (imap_master_client_parse_input(args, pool, &input, &master_input,
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync i_error("imap-master: Failed to parse client input: %s", error);
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync if (imap_master_client_verify(&master_input, fd_client, &error) < 0) {
86abc60770f825f8c2ed4257675b50a08743b687vboxsync i_error("imap-master: Failed to verify client input: %s", error);
fc148a6b23d25a87561beaffe0ba06c3ba93bf5avboxsync /* NOTE: before client_create_from_input() on failures we need to close
fc148a6b23d25a87561beaffe0ba06c3ba93bf5avboxsync fd_client, but afterward it gets closed by client_destroy() */
fc148a6b23d25a87561beaffe0ba06c3ba93bf5avboxsync ret = client_create_from_input(&input, fd_client, fd_client,
6bac87a5a3b46a6e4abed909c4d4f63a1058abbavboxsync i_error("imap-master(%s): Failed to create client: %s",
6bac87a5a3b46a6e4abed909c4d4f63a1058abbavboxsync master_service_client_connection_destroyed(master_service);
6bac87a5a3b46a6e4abed909c4d4f63a1058abbavboxsync /* log prefix is set at this point, so we don't need to add the
6bac87a5a3b46a6e4abed909c4d4f63a1058abbavboxsync username anymore to the log messages */
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync " bytes to client's input stream",
6bac87a5a3b46a6e4abed909c4d4f63a1058abbavboxsync "-Couldn't add client input\n");
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync client_destroy(imap_client, "Client initialization failed");
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync ret = imap_state_import_internal(imap_client, master_input.state->data,
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync if (ret <= 0) {
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync i_error("imap-master: Failed to import client state: %s", error);
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync client_destroy(imap_client, "Client state initialization failed");
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync /* make sure all pending input gets handled */
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync /* we'll always disconnect the client afterwards */
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsyncimap_master_client_input_line(struct connection *conn, const char *line)
6bac87a5a3b46a6e4abed909c4d4f63a1058abbavboxsync char *const *args;
08a56d5836eceeb24642b61eaa52a4edb0a7b482vboxsync if (connection_verify_version(conn, t_strsplit_tabescaped(line)) < 0)
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync fd_client = i_stream_unix_get_read_fd(conn->input);
6bac87a5a3b46a6e4abed909c4d4f63a1058abbavboxsync i_error("imap-master: IMAP client fd not received");
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync pool = pool_alloconly_create("imap master client cmd", 1024);
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync ret = imap_master_client_input_args(conn, (void *)args, fd_client, pool);
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync connection_init_server(master_clients, &client->conn,
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync client->conn.input = i_stream_create_unix(fd, (size_t)-1);
6bac87a5a3b46a6e4abed909c4d4f63a1058abbavboxsync /* read the first file descriptor that we can */
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync .input_max_size = 0, /* don't auto-create istream */
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsyncstatic const struct connection_vfuncs client_vfuncs = {