Skip to content

Commit

Permalink
lib-smtp: server: Change command hooks API to allow many parallel hoo…
Browse files Browse the repository at this point in the history
…ks with individual context.

This e.g. allows many server plugins to hook into command execution without
interfering with eachother.
  • Loading branch information
stephanbosch authored and villesavolainen committed Feb 12, 2019
1 parent f53edc2 commit a877a68
Show file tree
Hide file tree
Showing 24 changed files with 372 additions and 250 deletions.
18 changes: 11 additions & 7 deletions src/lib-smtp/smtp-server-cmd-auth.c
Expand Up @@ -47,7 +47,9 @@ void smtp_server_cmd_auth_success(struct smtp_server_cmd_ctx *cmd,
(success_msg == NULL ? "Logged in." : success_msg));
}

static void cmd_auth_completed(struct smtp_server_cmd_ctx *cmd)
static void
cmd_auth_completed(struct smtp_server_cmd_ctx *cmd,
struct smtp_server_cmd_auth *data ATTR_UNUSED)
{
struct smtp_server_connection *conn = cmd->conn;
struct smtp_server_command *command = cmd->cmd;
Expand Down Expand Up @@ -158,7 +160,9 @@ void smtp_server_cmd_auth_send_challenge(struct smtp_server_cmd_ctx *cmd,
smtp_server_command_input_capture(cmd, cmd_auth_input);
}

static void cmd_auth_start(struct smtp_server_cmd_ctx *cmd)
static void
cmd_auth_start(struct smtp_server_cmd_ctx *cmd,
struct smtp_server_cmd_auth *data)
{
struct smtp_server_connection *conn = cmd->conn;
struct smtp_server_command *command = cmd->cmd;
Expand All @@ -178,8 +182,7 @@ static void cmd_auth_start(struct smtp_server_cmd_ctx *cmd)
i_assert(callbacks != NULL && callbacks->conn_cmd_auth != NULL);

/* specific implementation of AUTH command */
ret = callbacks->conn_cmd_auth(conn->context, cmd,
(struct smtp_server_cmd_auth *)command->data);
ret = callbacks->conn_cmd_auth(conn->context, cmd, data);
i_assert(ret == 0 || smtp_server_command_is_replied(command));

if (ret == 0)
Expand Down Expand Up @@ -245,8 +248,9 @@ void smtp_server_cmd_auth(struct smtp_server_cmd_ctx *cmd,
auth_data = p_new(cmd->pool, struct smtp_server_cmd_auth, 1);
auth_data->sasl_mech = p_strdup(cmd->pool, sasl_mech);
auth_data->initial_response = p_strdup(cmd->pool, initial_response);
command->data = (void*)auth_data;

command->hook_next = cmd_auth_start;
command->hook_completed = cmd_auth_completed;
smtp_server_command_add_hook(command, SMTP_SERVER_COMMAND_HOOK_NEXT,
cmd_auth_start, auth_data);
smtp_server_command_add_hook(command, SMTP_SERVER_COMMAND_HOOK_COMPLETED,
cmd_auth_completed, auth_data);
}
96 changes: 62 additions & 34 deletions src/lib-smtp/smtp-server-cmd-data.c
Expand Up @@ -126,11 +126,12 @@ bool smtp_server_connection_data_check_state(struct smtp_server_cmd_ctx *cmd)
return TRUE;
}

static void cmd_data_destroy(struct smtp_server_cmd_ctx *cmd)
static void
cmd_data_destroy(struct smtp_server_cmd_ctx *cmd,
struct cmd_data_context *data_cmd)
{
struct smtp_server_connection *conn = cmd->conn;
struct smtp_server_command *command = cmd->cmd;
struct cmd_data_context *data_cmd = command->data;

i_assert(data_cmd != NULL);

Expand All @@ -145,7 +146,9 @@ static void cmd_data_destroy(struct smtp_server_cmd_ctx *cmd)
i_stream_unref(&data_cmd->chunk_input);
}

static void cmd_data_replied(struct smtp_server_cmd_ctx *cmd)
static void
cmd_data_replied(struct smtp_server_cmd_ctx *cmd,
struct cmd_data_context *data_cmd ATTR_UNUSED)
{
struct smtp_server_connection *conn = cmd->conn;
struct smtp_server_command *command = cmd->cmd;
Expand All @@ -158,11 +161,11 @@ static void cmd_data_replied(struct smtp_server_cmd_ctx *cmd)
smtp_server_command_input_unlock(cmd);
}

static void cmd_data_completed(struct smtp_server_cmd_ctx *cmd)
static void
cmd_data_completed(struct smtp_server_cmd_ctx *cmd,
struct cmd_data_context *data_cmd)
{
struct smtp_server_connection *conn = cmd->conn;
struct smtp_server_command *command = cmd->cmd;
struct cmd_data_context *data_cmd = command->data;

i_assert(data_cmd != NULL);
i_stream_unref(&data_cmd->chunk_input);
Expand All @@ -171,11 +174,12 @@ static void cmd_data_completed(struct smtp_server_cmd_ctx *cmd)
smtp_server_connection_reset_state(conn);
}

static void cmd_data_chunk_replied(struct smtp_server_cmd_ctx *cmd)
static void
cmd_data_chunk_replied(struct smtp_server_cmd_ctx *cmd,
struct cmd_data_context *data_cmd)
{
struct smtp_server_connection *conn = cmd->conn;
struct smtp_server_command *command = cmd->cmd;
struct cmd_data_context *data_cmd = command->data;

i_assert(data_cmd != NULL);

Expand All @@ -188,7 +192,9 @@ static void cmd_data_chunk_replied(struct smtp_server_cmd_ctx *cmd)
conn->state.data_failed = TRUE;
}

static void cmd_data_chunk_completed(struct smtp_server_cmd_ctx *cmd)
static void
cmd_data_chunk_completed(struct smtp_server_cmd_ctx *cmd,
struct cmd_data_context *data_cmd ATTR_UNUSED)
{
struct smtp_server_connection *conn = cmd->conn;
struct smtp_server_command *command = cmd->cmd;
Expand Down Expand Up @@ -322,12 +328,13 @@ static void cmd_data_input(struct smtp_server_cmd_ctx *cmd)
(void)cmd_data_handle_input(cmd);
}

static void cmd_data_next(struct smtp_server_cmd_ctx *cmd)
static void
cmd_data_next(struct smtp_server_cmd_ctx *cmd,
struct cmd_data_context *data_cmd)
{
struct smtp_server_connection *conn = cmd->conn;
const struct smtp_server_callbacks *callbacks = conn->callbacks;
struct smtp_server_command *command = cmd->cmd;
struct cmd_data_context *data_cmd = command->data;
int ret;

/* this command is next to send a reply */
Expand Down Expand Up @@ -399,12 +406,12 @@ static void cmd_data_next(struct smtp_server_cmd_ctx *cmd)
}
}

static void cmd_data_start_input(struct smtp_server_cmd_ctx *cmd,
struct istream *input)
static void
cmd_data_start_input(struct smtp_server_cmd_ctx *cmd,
struct cmd_data_context *data_cmd, struct istream *input)
{
struct smtp_server_connection *conn = cmd->conn;
struct smtp_server_command *command = cmd->cmd;
struct cmd_data_context *data_cmd = command->data;

i_assert(data_cmd != NULL);

Expand All @@ -416,22 +423,31 @@ static void cmd_data_start_input(struct smtp_server_cmd_ctx *cmd,
if (data_cmd->client_input)
smtp_server_command_input_lock(cmd);

if (data_cmd->chunk_last)
command->hook_completed = cmd_data_completed;
else
command->hook_completed = cmd_data_chunk_completed;
if (data_cmd->chunk_last) {
smtp_server_command_add_hook(
command, SMTP_SERVER_COMMAND_HOOK_COMPLETED,
cmd_data_completed, data_cmd);
} else {
smtp_server_command_add_hook(
command, SMTP_SERVER_COMMAND_HOOK_COMPLETED,
cmd_data_chunk_completed, data_cmd);
}

if (conn->state.pending_mail_cmds == 0 &&
conn->state.pending_rcpt_cmds == 0) {
cmd_data_next(cmd);
cmd_data_next(cmd, data_cmd);
} else {
command->hook_next = cmd_data_next;
smtp_server_command_add_hook(
command, SMTP_SERVER_COMMAND_HOOK_NEXT,
cmd_data_next, data_cmd);
}
}

/* DATA command */

static void cmd_data_start(struct smtp_server_cmd_ctx *cmd)
static void
cmd_data_start(struct smtp_server_cmd_ctx *cmd,
struct cmd_data_context *data_cmd)
{
struct smtp_server_connection *conn = cmd->conn;
struct istream *dot_input;
Expand All @@ -458,7 +474,7 @@ static void cmd_data_start(struct smtp_server_cmd_ctx *cmd)

/* start reading message data from client */
dot_input = smtp_command_parse_data_with_dot(conn->smtp_parser);
cmd_data_start_input(cmd, dot_input);
cmd_data_start_input(cmd, data_cmd, dot_input);
i_stream_unref(&dot_input);
}

Expand All @@ -482,11 +498,15 @@ void smtp_server_cmd_data(struct smtp_server_cmd_ctx *cmd,
data_cmd->chunk_first = TRUE;
data_cmd->chunk_last = TRUE;
data_cmd->client_input = TRUE;
command->data = (void*)data_cmd;
command->data = data_cmd;

smtp_server_command_add_hook(command, SMTP_SERVER_COMMAND_HOOK_NEXT,
cmd_data_start, data_cmd);
smtp_server_command_add_hook(command, SMTP_SERVER_COMMAND_HOOK_REPLIED,
cmd_data_replied, data_cmd);
smtp_server_command_add_hook(command, SMTP_SERVER_COMMAND_HOOK_DESTROY,
cmd_data_destroy, data_cmd);

command->hook_next = cmd_data_start;
command->hook_replied = cmd_data_replied;
command->hook_destroy = cmd_data_destroy;
conn->state.pending_data_cmds++;
}

Expand All @@ -499,12 +519,15 @@ void smtp_server_connection_data_chunk_init(struct smtp_server_cmd_ctx *cmd)
struct cmd_data_context *data_cmd;

data_cmd = p_new(cmd->pool, struct cmd_data_context, 1);
command->data = (void *)data_cmd;
data_cmd->chunking = TRUE;
data_cmd->chunk_first = (conn->state.data_chunks++ == 0);
command->data = data_cmd;

smtp_server_command_add_hook(command, SMTP_SERVER_COMMAND_HOOK_REPLIED,
cmd_data_chunk_replied, data_cmd);
smtp_server_command_add_hook(command, SMTP_SERVER_COMMAND_HOOK_DESTROY,
cmd_data_destroy, data_cmd);

command->hook_replied = cmd_data_chunk_replied;
command->hook_destroy = cmd_data_destroy;
conn->state.pending_data_cmds++;

if (!conn->state.data_failed && conn->state.data_chain == NULL) {
Expand All @@ -522,8 +545,7 @@ int smtp_server_connection_data_chunk_add(struct smtp_server_cmd_ctx *cmd,
struct smtp_server_connection *conn = cmd->conn;
const struct smtp_server_settings *set = &conn->set;
struct smtp_server_command *command = cmd->cmd;
struct cmd_data_context *data_cmd =
(struct cmd_data_context *)command->data;
struct cmd_data_context *data_cmd = command->data;
uoff_t new_size;

i_assert(data_cmd != NULL);
Expand All @@ -540,16 +562,22 @@ int smtp_server_connection_data_chunk_add(struct smtp_server_cmd_ctx *cmd,
}
conn->state.data_size = new_size;

command->hook_replied = (chunk_last ?
cmd_data_replied : cmd_data_chunk_replied);
if (chunk_last) {
smtp_server_command_remove_hook(
command, SMTP_SERVER_COMMAND_HOOK_REPLIED,
cmd_data_chunk_replied);
smtp_server_command_add_hook(
command, SMTP_SERVER_COMMAND_HOOK_REPLIED,
cmd_data_replied, data_cmd);
}

data_cmd->chunk_input = chunk;
data_cmd->chunk_size = chunk_size;
data_cmd->chunk_last = chunk_last;
data_cmd->client_input = client_input;
i_stream_ref(chunk);

cmd_data_start_input(cmd, conn->state.data_chain_input);
cmd_data_start_input(cmd, data_cmd, conn->state.data_chain_input);
i_stream_unref(&conn->state.data_chain_input);
return 0;
}
Expand Down
20 changes: 10 additions & 10 deletions src/lib-smtp/smtp-server-cmd-helo.c
Expand Up @@ -8,12 +8,12 @@

/* EHLO, HELO commands */

static void cmd_helo_completed(struct smtp_server_cmd_ctx *cmd)
static void
cmd_helo_completed(struct smtp_server_cmd_ctx *cmd,
struct smtp_server_cmd_helo *data)
{
struct smtp_server_connection *conn = cmd->conn;
struct smtp_server_command *command = cmd->cmd;
struct smtp_server_cmd_helo *data =
(struct smtp_server_cmd_helo *)command->data;

i_assert(smtp_server_command_is_replied(command));
if (!smtp_server_command_replied_success(command)) {
Expand All @@ -34,12 +34,11 @@ static void cmd_helo_completed(struct smtp_server_cmd_ctx *cmd)
conn->helo.old_smtp = data->helo.old_smtp;
}

static void cmd_helo_next(struct smtp_server_cmd_ctx *cmd)
static void
cmd_helo_next(struct smtp_server_cmd_ctx *cmd,
struct smtp_server_cmd_helo *data)
{
struct smtp_server_connection *conn = cmd->conn;
struct smtp_server_command *command = cmd->cmd;
struct smtp_server_cmd_helo *data =
(struct smtp_server_cmd_helo *)command->data;

if (conn->helo.domain == NULL ||
strcmp(conn->helo.domain, data->helo.domain) != 0 ||
Expand Down Expand Up @@ -87,9 +86,10 @@ smtp_server_cmd_helo_run(struct smtp_server_cmd_ctx *cmd, const char *params,
if (conn->pending_helo == NULL)
conn->pending_helo = &helo_data->helo;

command->data = helo_data;
command->hook_next = cmd_helo_next;
command->hook_completed = cmd_helo_completed;
smtp_server_command_add_hook(command, SMTP_SERVER_COMMAND_HOOK_NEXT,
cmd_helo_next, helo_data);
smtp_server_command_add_hook(command, SMTP_SERVER_COMMAND_HOOK_COMPLETED,
cmd_helo_completed, helo_data);

smtp_server_command_ref(command);
if (callbacks != NULL && callbacks->conn_cmd_helo != NULL) {
Expand Down
28 changes: 19 additions & 9 deletions src/lib-smtp/smtp-server-cmd-mail.c
Expand Up @@ -11,29 +11,35 @@

/* MAIL command */

static void
cmd_mail_replied(struct smtp_server_cmd_ctx *cmd,
struct smtp_server_cmd_mail *data);

static bool
cmd_mail_check_state(struct smtp_server_cmd_ctx *cmd)
{
struct smtp_server_connection *conn = cmd->conn;
struct smtp_server_command *command = cmd->cmd;

if (conn->state.trans != NULL) {
if (command->hook_replied != NULL) {
if (!smtp_server_command_is_replied(command)) {
conn->state.pending_mail_cmds--;
command->hook_replied = NULL;
smtp_server_command_remove_hook(
command, SMTP_SERVER_COMMAND_HOOK_REPLIED,
cmd_mail_replied);
}
smtp_server_reply(cmd, 503, "5.5.0", "MAIL already given");
return FALSE;
}
return TRUE;
}

static void cmd_mail_replied(struct smtp_server_cmd_ctx *cmd)
static void
cmd_mail_replied(struct smtp_server_cmd_ctx *cmd,
struct smtp_server_cmd_mail *data)
{
struct smtp_server_connection *conn = cmd->conn;
struct smtp_server_command *command = cmd->cmd;
struct smtp_server_cmd_mail *data =
(struct smtp_server_cmd_mail *)command->data;

i_assert(conn->state.pending_mail_cmds > 0);
conn->state.pending_mail_cmds--;
Expand All @@ -50,7 +56,9 @@ static void cmd_mail_replied(struct smtp_server_cmd_ctx *cmd)
data->path, &data->params, &data->timestamp);
}

static void cmd_mail_recheck(struct smtp_server_cmd_ctx *cmd)
static void
cmd_mail_recheck(struct smtp_server_cmd_ctx *cmd,
struct smtp_server_cmd_mail *data ATTR_UNUSED)
{
struct smtp_server_connection *conn = cmd->conn;

Expand Down Expand Up @@ -161,9 +169,11 @@ void smtp_server_cmd_mail(struct smtp_server_cmd_ctx *cmd,
mail_data->path = smtp_address_clone(cmd->pool, path);
mail_data->timestamp = ioloop_timeval;

command->data = mail_data;
command->hook_next = cmd_mail_recheck;
command->hook_replied = cmd_mail_replied;
smtp_server_command_add_hook(command, SMTP_SERVER_COMMAND_HOOK_NEXT,
cmd_mail_recheck, mail_data);
smtp_server_command_add_hook(command, SMTP_SERVER_COMMAND_HOOK_REPLIED,
cmd_mail_replied, mail_data);

smtp_server_connection_set_state(conn, SMTP_SERVER_STATE_MAIL_FROM);
conn->state.pending_mail_cmds++;

Expand Down

0 comments on commit a877a68

Please sign in to comment.