diff options
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-left | 148 |
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) + |