static void
service_dup_fds(struct service *service)
{
struct service_listener *const *listeners;
ARRAY_TYPE(dup2) dups;
string_t *listener_settings;
int fd = MASTER_LISTEN_FD_FIRST;
unsigned int i, count, socket_listener_count;
/* stdin/stdout is already redirected to /dev/null. Other master fds
should have been opened with fd_close_on_exec() so we don't have to
worry about them.
because the destination fd might be another one's source fd we have
to be careful not to overwrite anything. dup() the fd when needed */
socket_listener_count = 0;
listeners = array_get(&service->listeners, &count);
t_array_init(&dups, count + 10);
switch (service->type) {
case SERVICE_TYPE_LOG:
i_assert(fd == MASTER_LISTEN_FD_FIRST);
services_log_dup2(&dups, service->list, fd,
&socket_listener_count);
fd += socket_listener_count;
break;
case SERVICE_TYPE_ANVIL:
dup2_append(&dups, service_anvil_global->log_fdpass_fd[0],
MASTER_ANVIL_LOG_FDPASS_FD);
/* nonblocking anvil fd must be the first one. anvil treats it
as the master's fd */
dup2_append(&dups, service_anvil_global->nonblocking_fd[0], fd++);
dup2_append(&dups, service_anvil_global->blocking_fd[0], fd++);
socket_listener_count += 2;
break;
default:
break;
}
/* add listeners */
listener_settings = t_str_new(256);
for (i = 0; i < count; i++) {
if (listeners[i]->fd != -1) {
str_truncate(listener_settings, 0);
str_append_tabescaped(listener_settings, listeners[i]->name);
if (listeners[i]->type == SERVICE_LISTENER_INET) {
if (listeners[i]->set.inetset.set->ssl)
str_append(listener_settings, "\tssl");
if (listeners[i]->set.inetset.set->haproxy)
str_append(listener_settings, "\thaproxy");
}
dup2_append(&dups, listeners[i]->fd, fd++);
env_put(t_strdup_printf("SOCKET%d_SETTINGS=%s",
socket_listener_count, str_c(listener_settings)));
socket_listener_count++;
}
}
if (service->login_notify_fd != -1) {
dup2_append(&dups, service->login_notify_fd,
MASTER_LOGIN_NOTIFY_FD);
}
switch (service->type) {
case SERVICE_TYPE_LOG:
case SERVICE_TYPE_ANVIL:
case SERVICE_TYPE_CONFIG:
dup2_append(&dups, dev_null_fd, MASTER_ANVIL_FD);
break;
case SERVICE_TYPE_UNKNOWN:
case SERVICE_TYPE_LOGIN:
case SERVICE_TYPE_STARTUP:
dup2_append(&dups, service_anvil_global->blocking_fd[1],
MASTER_ANVIL_FD);
break;
}
dup2_append(&dups, service->status_fd[1], MASTER_STATUS_FD);
if (service->type != SERVICE_TYPE_ANVIL) {
dup2_append(&dups, service->master_dead_pipe_fd[1],
MASTER_DEAD_FD);
} else {
dup2_append(&dups, global_master_dead_pipe_fd[1],
MASTER_DEAD_FD);
}
if (service->type == SERVICE_TYPE_LOG) {
/* keep stderr as-is. this is especially important when
log_path=/dev/stderr, but might be helpful even in other
situations for logging startup errors */
} else {
/* set log file to stderr. dup2() here immediately so that
we can set up logging to it without causing any log messages
to be lost. */
i_assert(service->log_fd[1] != -1);
env_put("LOG_SERVICE=1");
if (dup2(service->log_fd[1], STDERR_FILENO) < 0)
//.........这里部分代码省略.........
static int parse_next_header(struct message_parser_ctx *ctx,
struct message_block *block_r)
{
struct message_part *part = ctx->part;
struct message_header_line *hdr;
struct message_boundary *boundary;
bool full;
int ret;
if ((ret = message_parser_read_more(ctx, block_r, &full)) == 0)
return ret;
if (ret > 0 && block_is_at_eoh(block_r) &&
ctx->last_boundary != NULL &&
(part->flags & MESSAGE_PART_FLAG_IS_MIME) != 0) {
/* we are at the end of headers and we've determined that we're
going to start a multipart. add the boundary already here
at this point so we can reliably determine whether the
"\n--boundary" belongs to us or to a previous boundary.
this is a problem if the boundary prefixes are identical,
because MIME requires only the prefix to match. */
parse_next_body_multipart_init(ctx);
ctx->multipart = TRUE;
}
/* before parsing the header see if we can find a --boundary from here.
we're guaranteed to be at the beginning of the line here. */
if (ret > 0) {
ret = ctx->boundaries == NULL ? -1 :
boundary_line_find(ctx, block_r->data,
block_r->size, full, &boundary);
if (ret > 0 && boundary->part == ctx->part) {
/* our own body begins with our own --boundary.
we don't want to handle that yet. */
ret = -1;
}
}
if (ret < 0) {
/* no boundary */
ret = message_parse_header_next(ctx->hdr_parser_ctx, &hdr);
if (ret == 0 || (ret < 0 && ctx->input->stream_errno != 0)) {
ctx->want_count = i_stream_get_data_size(ctx->input) + 1;
return ret;
}
} else if (ret == 0) {
/* need more data */
return 0;
} else {
/* boundary found. stop parsing headers here. The previous
[CR]LF belongs to the MIME boundary though. */
if (ctx->prev_hdr_newline_size > 0) {
i_assert(ctx->part->header_size.lines > 0);
/* remove the newline size from the MIME header */
ctx->part->header_size.lines--;
ctx->part->header_size.physical_size -=
ctx->prev_hdr_newline_size;
ctx->part->header_size.virtual_size -= 2;
/* add the newline size to the parent's body */
ctx->part->parent->body_size.lines++;
ctx->part->parent->body_size.physical_size +=
ctx->prev_hdr_newline_size;
ctx->part->parent->body_size.virtual_size += 2;
}
hdr = NULL;
}
if (hdr != NULL) {
if (hdr->eoh)
;
else if (strcasecmp(hdr->name, "Mime-Version") == 0) {
/* it's MIME. Content-* headers are valid */
part->flags |= MESSAGE_PART_FLAG_IS_MIME;
} else if (strcasecmp(hdr->name, "Content-Type") == 0) {
if ((ctx->flags &
MESSAGE_PARSER_FLAG_MIME_VERSION_STRICT) == 0)
part->flags |= MESSAGE_PART_FLAG_IS_MIME;
if (hdr->continues)
hdr->use_full_value = TRUE;
else T_BEGIN {
parse_content_type(ctx, hdr);
} T_END;
}
block_r->hdr = hdr;
block_r->size = 0;
ctx->prev_hdr_newline_size = hdr->no_newline ? 0 :
(hdr->crlf_newline ? 2 : 1);
return 1;
}
/* end of headers */
if ((part->flags & MESSAGE_PART_FLAG_IS_MIME) == 0) {
/* It's not MIME. Reset everything we found from
Content-Type. */
i_assert(!ctx->multipart);
part->flags = 0;
}
ctx->last_boundary = NULL;
//.........这里部分代码省略.........
static void
dsync_brain_mailbox_tree_add_delete(struct dsync_mailbox_tree *tree,
struct dsync_mailbox_tree *other_tree,
const struct dsync_mailbox_delete *other_del)
{
const struct dsync_mailbox_node *node;
struct dsync_mailbox_node *other_node, *old_node;
const char *name;
/* see if we can find the deletion based on mailbox tree that should
still have the mailbox */
node = dsync_mailbox_tree_find_delete(tree, other_del);
if (node == NULL)
return;
switch (other_del->type) {
case DSYNC_MAILBOX_DELETE_TYPE_MAILBOX:
/* mailbox is always deleted */
break;
case DSYNC_MAILBOX_DELETE_TYPE_DIR:
if (other_del->timestamp <= node->last_renamed_or_created) {
/* we don't want to delete this directory, we already
have a newer timestamp for it */
return;
}
break;
case DSYNC_MAILBOX_DELETE_TYPE_UNSUBSCRIBE:
if (other_del->timestamp <= node->last_subscription_change) {
/* we don't want to unsubscribe, since we already have
a newer subscription timestamp */
return;
}
break;
}
/* make a node for it in the other mailbox tree */
name = dsync_mailbox_node_get_full_name(tree, node);
other_node = dsync_mailbox_tree_get(other_tree, name);
if (other_node->existence == DSYNC_MAILBOX_NODE_EXISTS &&
(!guid_128_is_empty(other_node->mailbox_guid) ||
other_del->type != DSYNC_MAILBOX_DELETE_TYPE_MAILBOX)) {
/* other side has already created a new mailbox or
directory with this name, we can't delete it */
return;
}
/* ok, mark the other node deleted */
if (other_del->type == DSYNC_MAILBOX_DELETE_TYPE_MAILBOX) {
memcpy(other_node->mailbox_guid, node->mailbox_guid,
sizeof(other_node->mailbox_guid));
}
i_assert(other_node->ns == NULL || other_node->ns == node->ns);
other_node->ns = node->ns;
if (other_del->type != DSYNC_MAILBOX_DELETE_TYPE_UNSUBSCRIBE)
other_node->existence = DSYNC_MAILBOX_NODE_DELETED;
else {
other_node->last_subscription_change = other_del->timestamp;
other_node->subscribed = FALSE;
}
if (dsync_mailbox_tree_guid_hash_add(other_tree, other_node,
&old_node) < 0)
i_unreached();
}
void client_command_free(struct client_command_context **_cmd)
{
struct client_command_context *cmd = *_cmd;
struct client *client = cmd->client;
enum client_command_state state = cmd->state;
*_cmd = NULL;
i_assert(client->output_cmd_lock == NULL);
/* reset input idle time because command output might have taken a
long time and we don't want to disconnect client immediately then */
client->last_input = ioloop_time;
timeout_reset(client->to_idle);
if (cmd->cancel) {
cmd->cancel = FALSE;
client_send_tagline(cmd, "NO Command cancelled.");
}
if (!cmd->param_error)
client->bad_counter = 0;
if (client->input_lock == cmd)
client->input_lock = NULL;
if (client->mailbox_change_lock == cmd)
client->mailbox_change_lock = NULL;
if (cmd->parser != NULL) {
if (client->free_parser == NULL) {
imap_parser_reset(cmd->parser);
client->free_parser = cmd->parser;
} else {
imap_parser_unref(&cmd->parser);
}
}
client->command_queue_size--;
DLLIST_REMOVE(&client->command_queue, cmd);
cmd = NULL;
if (client->command_queue == NULL) {
/* no commands left in the queue, we can clear the pool */
p_clear(client->command_pool);
if (client->to_idle_output != NULL)
timeout_remove(&client->to_idle_output);
}
imap_client_notify_command_freed(client);
imap_refresh_proctitle();
/* if command finished from external event, check input for more
unhandled commands since we may not be executing from client_input
or client_output. */
if (state == CLIENT_COMMAND_STATE_WAIT_EXTERNAL &&
!client->disconnected) {
client_add_missing_io(client);
if (client->to_delayed_input == NULL) {
client->to_delayed_input =
timeout_add(0, client_input, client);
}
}
}
static void client_default_destroy(struct client *client, const char *reason)
{
struct client_command_context *cmd;
const char *cmd_status = "";
i_assert(!client->destroyed);
client->destroyed = TRUE;
if (!client->disconnected) {
client->disconnected = TRUE;
if (reason == NULL) {
reason = io_stream_get_disconnect_reason(client->input,
client->output);
cmd_status = client_get_commands_status(client);
}
i_info("%s%s %s", reason, cmd_status, client_stats(client));
}
i_stream_close(client->input);
o_stream_close(client->output);
/* finish off all the queued commands. */
if (client->output_cmd_lock != NULL)
client_command_cancel(&client->output_cmd_lock);
while (client->command_queue != NULL) {
cmd = client->command_queue;
client_command_cancel(&cmd);
}
/* handle the input_lock command last. it might have been waiting on
other queued commands (although we probably should just drop the
command at that point since it hasn't started running. but this may
change in future). */
if (client->input_lock != NULL)
client_command_cancel(&client->input_lock);
if (client->mailbox != NULL) {
client_search_updates_free(client);
mailbox_free(&client->mailbox);
}
if (client->notify_ctx != NULL)
imap_notify_deinit(&client->notify_ctx);
if (client->urlauth_ctx != NULL)
imap_urlauth_deinit(&client->urlauth_ctx);
if (client->anvil_sent) {
master_service_anvil_send(master_service, t_strconcat(
"DISCONNECT\t", my_pid, "\timap/",
mail_user_get_anvil_userip_ident(client->user),
"\n", NULL));
}
mail_user_unref(&client->user);
if (client->free_parser != NULL)
imap_parser_unref(&client->free_parser);
if (client->io != NULL)
io_remove(&client->io);
if (client->to_idle_output != NULL)
timeout_remove(&client->to_idle_output);
if (client->to_delayed_input != NULL)
timeout_remove(&client->to_delayed_input);
timeout_remove(&client->to_idle);
i_stream_destroy(&client->input);
o_stream_destroy(&client->output);
net_disconnect(client->fd_in);
if (client->fd_in != client->fd_out)
net_disconnect(client->fd_out);
if (array_is_created(&client->search_saved_uidset))
array_free(&client->search_saved_uidset);
if (array_is_created(&client->search_updates))
array_free(&client->search_updates);
pool_unref(&client->command_pool);
mail_storage_service_user_free(&client->service_user);
imap_client_count--;
DLLIST_REMOVE(&imap_clients, client);
pool_unref(&client->pool);
master_service_client_connection_destroyed(master_service);
imap_refresh_proctitle();
}
请发表评论