summaryrefslogtreecommitdiff
path: root/mail/dbmail/files/patch-0007-Disconnect-IMAP-clients-if-only-few-free-FDs-left
diff options
context:
space:
mode:
Diffstat (limited to 'mail/dbmail/files/patch-0007-Disconnect-IMAP-clients-if-only-few-free-FDs-left')
-rw-r--r--mail/dbmail/files/patch-0007-Disconnect-IMAP-clients-if-only-few-free-FDs-left148
1 files changed, 148 insertions, 0 deletions
diff --git a/mail/dbmail/files/patch-0007-Disconnect-IMAP-clients-if-only-few-free-FDs-left b/mail/dbmail/files/patch-0007-Disconnect-IMAP-clients-if-only-few-free-FDs-left
new file mode 100644
index 000000000000..eca0ae403168
--- /dev/null
+++ b/mail/dbmail/files/patch-0007-Disconnect-IMAP-clients-if-only-few-free-FDs-left
@@ -0,0 +1,148 @@
+From 6b7eccfec4f76b7d9d1f865caf741ff3214b5964 Mon Sep 17 00:00:00 2001
+From: Pavlo Lavrenenko <santa.ssh@gmail.com>
+Date: Thu, 2 Jun 2016 08:18:51 +0300
+Subject: [PATCH 07/33] Disconnect IMAP clients if only few free FDs left (#37)
+
+After network connection to DB server goes down the processing of IMAP session
+stalls: DB connection pool becomes exhausted as active connections do not
+close till TCP timeout kicks in (true at least for Oracle). While DBMail still
+accepts incoming connections it quickly reaches the RLIMIT_NOFILE and becomes
+unresponsive. Send BYE response if the number of opened FDs reaches the
+RLIMIT_NOFILE value.
+---
+ src/dbmail.h.in | 5 +++++
+ src/dm_misc.c | 20 ++++++++++++++++++++
+ src/dm_misc.h | 8 ++++++++
+ src/imap4.c | 23 ++++++++++++++++++++++-
+ 4 files changed, 55 insertions(+), 1 deletion(-)
+
+diff --git src/dbmail.h.in src/dbmail.h.in
+index d826dc3..17215ef 100644
+--- src/dbmail.h.in
++++ src/dbmail.h.in
+@@ -69,12 +69,14 @@
+ #include <string.h>
+ #include <strings.h>
+ #include <sysexits.h>
++#include <dirent.h>
+ #include <sys/types.h>
+ #include <sys/stat.h>
+ #include <sys/mman.h>
+ #include <sys/socket.h>
+ #include <sys/un.h>
+ #include <sys/time.h>
++#include <sys/resource.h>
+ #include <sys/wait.h>
+ #include <sys/ipc.h>
+ #include <sys/shm.h>
+@@ -252,6 +254,9 @@
+ /* input reading linelimit */
+ #define MAX_LINESIZE (64*1024)
+
++/* minumun number of free file descriptors required to run the daemon */
++#define FREE_DF_THRESHOLD 16
++
+ /* string length for query */
+ #define DEF_QUERYSIZE (32*1024)
+ #define DEF_FRAGSIZE 256
+diff --git src/dm_misc.c src/dm_misc.c
+index e27ef34..e795de1 100644
+--- src/dm_misc.c
++++ src/dm_misc.c
+@@ -104,6 +104,26 @@ int drop_privileges(char *newuser, char *newgroup)
+ return 0;
+ }
+
++int get_opened_fd_count(void)
++{
++ DIR* dir = NULL;
++ struct dirent* entry = NULL;
++ char buf[32];
++ int fd_count = 0;
++
++ snprintf(buf, 32, "/proc/%i/fd/", getpid());
++
++ dir = opendir(buf);
++ if (dir == NULL)
++ return -1;
++
++ while ((entry = readdir(dir)) != NULL)
++ fd_count++;
++ closedir(dir);
++
++ return fd_count - 2; /* exclude '.' and '..' entries */
++}
++
+ void create_unique_id(char *target, uint64_t message_idnr)
+ {
+ char md5_str[FIELDSIZE];
+diff --git src/dm_misc.h src/dm_misc.h
+index 9660dfa..b6cf24f 100644
+--- src/dm_misc.h
++++ src/dm_misc.h
+@@ -45,6 +45,14 @@ void g_string_maybe_shrink(GString *s);
+ int drop_privileges(char *newuser, char *newgroup);
+
+ /**
++ \brief get the number of opened files (requires /proc mounted)
++ \return
++ - -1 on error
++ - number of opened files
++*/
++int get_opened_fd_count(void);
++
++/**
+ * \brief create a unique id for a message (used for pop, stored per message)
+ * \param target target string. Length should be UID_SIZE
+ * \param message_idnr message_idnr of message
+diff --git src/imap4.c src/imap4.c
+index 0532f2e..e523edc 100644
+--- src/imap4.c
++++ src/imap4.c
+@@ -351,6 +351,12 @@ static void send_greeting(ImapSession *session)
+ dbmail_imap_session_set_state(session, CLIENTSTATE_NON_AUTHENTICATED);
+ }
+
++static void disconnect_user(ImapSession *session)
++{
++ imap_session_printf(session, "* BYE [Service unavailable.]\r\n");
++ imap_handle_abort(session);
++}
++
+ /*
+ * the default timeout callback */
+
+@@ -601,6 +607,8 @@ int imap_handle_connection(client_sock *c)
+ {
+ ImapSession *session;
+ ClientBase_T *ci;
++ struct rlimit fd_limit;
++ int fd_count;
+
+ ci = client_init(c);
+
+@@ -617,7 +625,20 @@ int imap_handle_connection(client_sock *c)
+ Capa_remove(session->capa, "LOGINDISABLED");
+ }
+
+- send_greeting(session);
++ fd_count = get_opened_fd_count();
++ if (fd_count < 0 || getrlimit(RLIMIT_NPROC, &fd_limit) < 0) {
++ TRACE(TRACE_ERR,
++ "[%p] failed to retrieve fd limits, dropping client connection",
++ session);
++ disconnect_user(session);
++ } else if (fd_limit.rlim_cur - fd_count < FREE_DF_THRESHOLD) {
++ TRACE(TRACE_WARNING,
++ "[%p] fd count [%d], fd limit [%d], fd threshold [%d]: dropping client connection",
++ session, fd_count, fd_limit.rlim_cur, FREE_DF_THRESHOLD);
++ disconnect_user(session);
++ } else {
++ send_greeting(session);
++ }
+
+ reset_callbacks(session);
+
+--
+2.10.1 (Apple Git-78)
+