dovecot-2.2: pop3_lock_session: Use a separate dovecot-pop3-sess...

dovecot at dovecot.org dovecot at dovecot.org
Sat Feb 16 18:22:36 EET 2013


details:   http://hg.dovecot.org/dovecot-2.2/rev/473c0389eb10
changeset: 15787:473c0389eb10
user:      Timo Sirainen <tss at iki.fi>
date:      Sat Feb 16 18:22:23 2013 +0200
description:
pop3_lock_session: Use a separate dovecot-pop3-session.lock file instead of mailbox lock.
This changes the behavior in a way that it's now possible for IMAP sessions
to expunge mails during a POP3 session. But now it's no longer possible for
POP3 sessions to hang new mail deliveries.

diffstat:

 doc/example-config/conf.d/20-pop3.conf |   2 +-
 src/pop3/pop3-client.c                 |  76 +++++++++++++++++++++++++++++++--
 src/pop3/pop3-client.h                 |   3 +
 3 files changed, 74 insertions(+), 7 deletions(-)

diffs (163 lines):

diff -r 35194cf0693e -r 473c0389eb10 doc/example-config/conf.d/20-pop3.conf
--- a/doc/example-config/conf.d/20-pop3.conf	Sat Feb 16 17:58:20 2013 +0200
+++ b/doc/example-config/conf.d/20-pop3.conf	Sat Feb 16 18:22:23 2013 +0200
@@ -16,7 +16,7 @@
   # If mail has X-UIDL header, use it as the mail's UIDL.
   #pop3_reuse_xuidl = no
 
-  # Keep the mailbox locked for the entire POP3 session.
+  # Allow only one POP3 session to run simultaneously for the same user.
   #pop3_lock_session = no
 
   # POP3 requires message sizes to be listed as if they had CR+LF linefeeds.
diff -r 35194cf0693e -r 473c0389eb10 src/pop3/pop3-client.c
--- a/src/pop3/pop3-client.c	Sat Feb 16 17:58:20 2013 +0200
+++ b/src/pop3/pop3-client.c	Sat Feb 16 18:22:23 2013 +0200
@@ -10,6 +10,7 @@
 #include "str.h"
 #include "llist.h"
 #include "hostpid.h"
+#include "file-dotlock.h"
 #include "var-expand.h"
 #include "master-service.h"
 #include "mail-storage.h"
@@ -37,6 +38,9 @@
    transaction. This allows the mailbox to become unlocked. */
 #define CLIENT_COMMIT_TIMEOUT_MSECS (10*1000)
 
+#define POP3_LOCK_FNAME "dovecot-pop3-session.lock"
+#define POP3_SESSION_DOTLOCK_STALE_TIMEOUT_SECS (60*5)
+
 extern struct pop3_client_vfuncs pop3_client_vfuncs;
 
 struct pop3_module_register pop3_module_register = { 0 };
@@ -49,6 +53,13 @@
 	MAIL_SORT_END
 };
 
+static const struct dotlock_settings session_dotlock_set = {
+	.timeout = 10,
+	.stale_timeout = POP3_SESSION_DOTLOCK_STALE_TIMEOUT_SECS,
+	.lock_suffix = "",
+	.use_io_notify = TRUE
+};
+
 static void client_input(struct client *client);
 static int client_output(struct client *client);
 
@@ -273,6 +284,49 @@
 	return mask;
 }
 
+static void pop3_lock_session_refresh(struct client *client)
+{
+	if (file_dotlock_touch(client->session_dotlock) < 0) {
+		client_send_line(client,
+			"-ERR [SYS/TEMP] Couldn't update POP3 session lock.");
+		client_destroy(client, "Couldn't lock POP3 session");
+	}
+}
+
+static int pop3_lock_session(struct client *client)
+{
+	const struct mail_storage_settings *mail_set =
+		mail_storage_service_user_get_mail_set(client->service_user);
+	struct dotlock_settings dotlock_set;
+	const char *dir, *path;
+	int ret;
+
+	if (!mailbox_list_get_root_path(client->inbox_ns->list,
+					MAILBOX_LIST_PATH_TYPE_DIR, &dir) &&
+	    !mailbox_list_get_root_path(client->inbox_ns->list,
+					MAILBOX_LIST_PATH_TYPE_INDEX, &dir)) {
+		i_error("pop3_lock_session: Storage has no root/index directory, "
+			"can't create a POP3 session lock file");
+		return -1;
+	}
+	path = t_strdup_printf("%s/"POP3_LOCK_FNAME, dir);
+
+	dotlock_set = session_dotlock_set;
+	dotlock_set.use_excl_lock = mail_set->dotlock_use_excl;
+	dotlock_set.nfs_flush = mail_set->mail_nfs_storage;
+
+	ret = file_dotlock_create(&dotlock_set, path, 0,
+				  &client->session_dotlock);
+	if (ret < 0)
+		i_error("file_dotlock_create(%s) failed: %m", path);
+	else if (ret > 0) {
+		client->to_session_dotlock_refresh =
+			timeout_add(POP3_SESSION_DOTLOCK_STALE_TIMEOUT_SECS*1000,
+				    pop3_lock_session_refresh, client);
+	}
+	return ret;
+}
+
 int client_create(int fd_in, int fd_out, const char *session_id,
 		  struct mail_user *user,
 		  struct mail_storage_service_user *service_user,
@@ -284,6 +338,7 @@
         enum mailbox_flags flags;
 	const char *errmsg;
 	pool_t pool;
+	int ret;
 
 	/* always use nonblocking I/O */
 	net_set_nonblock(fd_in, TRUE);
@@ -308,10 +363,8 @@
         client->last_input = ioloop_time;
 	client->to_idle = timeout_add(CLIENT_IDLE_TIMEOUT_MSECS,
 				      client_idle_timeout, client);
-	if (!set->pop3_lock_session) {
-		client->to_commit = timeout_add(CLIENT_COMMIT_TIMEOUT_MSECS,
-						client_commit_timeout, client);
-	}
+	client->to_commit = timeout_add(CLIENT_COMMIT_TIMEOUT_MSECS,
+					client_commit_timeout, client);
 
 	client->user = user;
 
@@ -321,11 +374,17 @@
 	client->inbox_ns = mail_namespace_find_inbox(user->namespaces);
 	i_assert(client->inbox_ns != NULL);
 
+	if (set->pop3_lock_session && (ret = pop3_lock_session(client)) <= 0) {
+		client_send_line(client, ret < 0 ?
+			"-ERR [SYS/TEMP] Failed to create POP3 session lock." :
+			"-ERR [IN-USE] Mailbox is locked by another POP3 session.");
+		client_destroy(client, "Couldn't lock POP3 session");
+		return -1;
+	}
+
 	flags = MAILBOX_FLAG_POP3_SESSION;
 	if (!set->pop3_no_flag_updates)
 		flags |= MAILBOX_FLAG_DROP_RECENT;
-	if (set->pop3_lock_session)
-		flags |= MAILBOX_FLAG_KEEP_LOCKED;
 	client->mailbox = mailbox_alloc(client->inbox_ns->list, "INBOX", flags);
 	storage = mailbox_get_storage(client->mailbox);
 	if (mailbox_open(client->mailbox) < 0) {
@@ -508,6 +567,11 @@
 	}
 	mail_user_unref(&client->user);
 
+	if (client->session_dotlock != NULL)
+		file_dotlock_delete(&client->session_dotlock);
+	if (client->to_session_dotlock_refresh != NULL)
+		timeout_remove(&client->to_session_dotlock_refresh);
+
 	if (client->uidl_pool != NULL)
 		pool_unref(&client->uidl_pool);
 	i_free(client->message_sizes);
diff -r 35194cf0693e -r 473c0389eb10 src/pop3/pop3-client.h
--- a/src/pop3/pop3-client.h	Sat Feb 16 17:58:20 2013 +0200
+++ b/src/pop3/pop3-client.h	Sat Feb 16 18:22:23 2013 +0200
@@ -45,6 +45,9 @@
 	struct mailbox *mailbox;
 	struct mailbox_transaction_context *trans;
 
+	struct timeout *to_session_dotlock_refresh;
+	struct dotlock *session_dotlock;
+
 	time_t last_input, last_output;
 	unsigned int bad_counter;
 	unsigned int highest_expunged_fetch_msgnum;


More information about the dovecot-cvs mailing list