diff src/director/user-directory.c @ 22676:c9549bea9106

director: Don't send USERs in handshake that were already sent between handshake If the user was refreshed since the handshake was started, it means that the same user was already sent to the other side (added to the stream immediately after it was received/handled). There's no need to send it again. This fixes a potentally infinite handshake when users are rapidly changing and the handshake iterator never sees the end of the list. (Each refreshed user is moved to the end of the list, so handshaking can keep sending the same user over and over again.)
author Timo Sirainen <timo.sirainen@dovecot.fi>
date Sat, 25 Nov 2017 10:01:31 +0200
parents d689d7d99b4f
children cb108f786fb4
line wrap: on
line diff
--- a/src/director/user-directory.c	Sat Nov 25 10:05:27 2017 +0200
+++ b/src/director/user-directory.c	Sat Nov 25 10:01:31 2017 +0200
@@ -17,7 +17,7 @@
 
 struct user_directory_iter {
 	struct user_directory *dir;
-	struct user *pos;
+	struct user *pos, *stop_after_tail;
 };
 
 struct user_directory {
@@ -46,6 +46,10 @@
 	array_foreach(&dir->iters, iterp) {
 		if ((*iterp)->pos == user)
 			(*iterp)->pos = user->next;
+		if ((*iterp)->stop_after_tail == user) {
+			(*iterp)->stop_after_tail =
+				user->prev != NULL ? user->prev : user->next;
+		}
 	}
 }
 
@@ -291,13 +295,15 @@
 }
 
 struct user_directory_iter *
-user_directory_iter_init(struct user_directory *dir)
+user_directory_iter_init(struct user_directory *dir,
+			 bool iter_until_current_tail)
 {
 	struct user_directory_iter *iter;
 
 	iter = i_new(struct user_directory_iter, 1);
 	iter->dir = dir;
 	iter->pos = dir->head;
+	iter->stop_after_tail = iter_until_current_tail ? dir->tail : NULL;
 	array_append(&dir->iters, &iter, 1);
 	user_directory_drop_expired(dir);
 	return iter;
@@ -312,6 +318,10 @@
 		return NULL;
 
 	iter->pos = user->next;
+	if (user == iter->stop_after_tail) {
+		/* this is the last user we want to iterate */
+		iter->pos = NULL;
+	}
 	return user;
 }