src/master/dovecot
src/ssl-params/ssl-params
src/stats/stats
-src/old-stats/old-stats
src/plugins/fts-squat/squat-test
src/pop3-login/pop3-login
src/pop3/pop3
$(top_builddir)/src/lib-program-client/libprogram_client.la \
$(top_builddir)/src/lib-master/libmaster.la \
$(top_builddir)/src/lib-settings/libsettings.la \
- $(top_builddir)/src/lib-old-stats/libold_stats.la \
$(top_builddir)/src/lib-http/libhttp.la \
$(top_builddir)/src/lib-fs/libfs.la \
$(top_builddir)/src/lib-dict/libdict.la \
src/lib-settings/Makefile
src/lib-smtp/Makefile
src/lib-ssl-iostream/Makefile
-src/lib-old-stats/Makefile
src/lib-test/Makefile
src/lib-storage/Makefile
src/lib-storage/list/Makefile
src/replication/aggregator/Makefile
src/replication/replicator/Makefile
src/stats/Makefile
-src/old-stats/Makefile
src/util/Makefile
src/plugins/Makefile
src/plugins/acl/Makefile
src/plugins/quota-clone/Makefile
src/plugins/imap-quota/Makefile
src/plugins/replication/Makefile
-src/plugins/old-stats/Makefile
-src/plugins/imap-old-stats/Makefile
src/plugins/trash/Makefile
src/plugins/virtual/Makefile
src/plugins/welcome/Makefile
LIBDOVECOT_LIBFTS_DEPS="@LIBDOVECOT_LIBFTS@"
LIBDOVECOT_LUA_DEPS="@LIBDOVECOT_LUA@"
-LIBDOVECOT_INCLUDE="-I$(incdir) -I$(incdir)/src/lib -I$(incdir)/src/lib-dict -I$(incdir)/src/lib-dns -I$(incdir)/src/lib-http -I$(incdir)/src/lib-mail -I$(incdir)/src/lib-smtp -I$(incdir)/src/lib-imap -I$(incdir)/src/lib-imap -I$(incdir)/src/lib-fs -I$(incdir)/src/lib-charset -I$(incdir)/src/lib-auth -I$(incdir)/src/lib-master -I$(incdir)/src/lib-ssl-iostream -I$(incdir)/src/lib-compression -I$(incdir)/src/lib-settings -I$(incdir)/src/lib-test -I$(incdir)/src/lib-sasl -I$(incdir)/src/lib-old-stats -I$(incdir)/src/lib-dcrypt -I$(incdir)/src/lib-program-client"
+LIBDOVECOT_INCLUDE="-I$(incdir) -I$(incdir)/src/lib -I$(incdir)/src/lib-dict -I$(incdir)/src/lib-dns -I$(incdir)/src/lib-http -I$(incdir)/src/lib-mail -I$(incdir)/src/lib-smtp -I$(incdir)/src/lib-imap -I$(incdir)/src/lib-imap -I$(incdir)/src/lib-fs -I$(incdir)/src/lib-charset -I$(incdir)/src/lib-auth -I$(incdir)/src/lib-master -I$(incdir)/src/lib-ssl-iostream -I$(incdir)/src/lib-compression -I$(incdir)/src/lib-settings -I$(incdir)/src/lib-test -I$(incdir)/src/lib-sasl -I$(incdir)/src/lib-dcrypt -I$(incdir)/src/lib-program-client"
LIBDOVECOT_LDA_INCLUDE="-I$(incdir)/src/lib-lda -I$(incdir)/src/lda"
LIBDOVECOT_AUTH_INCLUDE="-I$(incdir)/src/auth"
LIBDOVECOT_DOVEADM_INCLUDE="-I$(incdir)/src/lib-doveadm -I$(incdir)/src/doveadm"
lib-dcrypt \
lib-dict \
lib-sasl \
- lib-old-stats \
lib-http \
lib-fs \
lib-mail \
util \
doveadm \
stats \
- old-stats \
plugins
+++ /dev/null
-noinst_LTLIBRARIES = libold_stats.la
-
-AM_CPPFLAGS = \
- -I$(top_srcdir)/src/lib \
- -I$(top_srcdir)/src/lib-master
-
-libold_stats_la_SOURCES = \
- stats.c \
- stats-connection.c \
- stats-parser.c
-
-headers = \
- stats.h \
- stats-connection.h \
- stats-parser.h
-
-pkginc_libdir = $(pkgincludedir)
-pkginc_lib_HEADERS = $(headers)
+++ /dev/null
-/* Copyright (c) 2011-2018 Dovecot authors, see the included COPYING file */
-
-#include "lib.h"
-#include "ioloop.h"
-#include "str.h"
-#include "master-service.h"
-#include "stats-connection.h"
-
-#include <unistd.h>
-#include <fcntl.h>
-
-#define STATS_EAGAIN_WARN_INTERVAL_SECS 30
-
-struct stats_connection {
- int refcount;
-
- int fd;
- char *path;
-
- bool open_failed;
- time_t next_warning_timestamp;
-};
-
-static bool stats_connection_open(struct stats_connection *conn)
-{
- if (conn->open_failed)
- return FALSE;
-
- conn->fd = open(conn->path, O_WRONLY | O_NONBLOCK);
- if (conn->fd == -1) {
- i_error("stats: open(%s) failed: %m", conn->path);
- conn->open_failed = TRUE;
- return FALSE;
- }
- return TRUE;
-}
-
-struct stats_connection *
-stats_connection_create(const char *path)
-{
- struct stats_connection *conn;
-
- conn = i_new(struct stats_connection, 1);
- conn->refcount = 1;
- conn->path = i_strdup(path);
- (void)stats_connection_open(conn);
- return conn;
-}
-
-void stats_connection_ref(struct stats_connection *conn)
-{
- conn->refcount++;
-}
-
-void stats_connection_unref(struct stats_connection **_conn)
-{
- struct stats_connection *conn = *_conn;
-
- i_assert(conn->refcount > 0);
- if (--conn->refcount > 0)
- return;
-
- *_conn = NULL;
- i_close_fd_path(&conn->fd, conn->path);
- i_free(conn->path);
- i_free(conn);
-}
-
-int stats_connection_send(struct stats_connection *conn, const string_t *str)
-{
- static bool pipe_warned = FALSE;
- ssize_t ret;
-
- /* if master process has been stopped (and restarted), don't even try
- to notify the stats process anymore. even if one exists, it doesn't
- know about us. */
- if (master_service_is_master_stopped(master_service))
- return -1;
-
- if (conn->fd == -1) {
- if (!stats_connection_open(conn))
- return -1;
- i_assert(conn->fd != -1);
- }
-
- if (str_len(str) > PIPE_BUF && !pipe_warned) {
- i_warning("stats update sent more bytes that PIPE_BUF "
- "(%zu > %u), this may break statistics",
- str_len(str), (unsigned int)PIPE_BUF);
- pipe_warned = TRUE;
- }
-
- ret = write(conn->fd, str_data(str), str_len(str));
- if (ret == (ssize_t)str_len(str)) {
- /* success */
- return 0;
- } else if (ret < 0 && errno == EAGAIN) {
- /* stats process is busy */
- if (ioloop_time > conn->next_warning_timestamp) {
- i_warning("write(%s) failed: %m (stats process is busy)", conn->path);
- conn->next_warning_timestamp = ioloop_time +
- STATS_EAGAIN_WARN_INTERVAL_SECS;
- }
- return -1;
- } else {
- /* error - reconnect */
- if (ret < 0) {
- /* don't log EPIPE errors. they can happen when
- Dovecot is stopped. */
- if (errno != EPIPE)
- i_error("write(%s) failed: %m", conn->path);
- } else if ((size_t)ret != str_len(str))
- i_error("write(%s) wrote partial update", conn->path);
- if (close(conn->fd) < 0)
- i_error("close(%s) failed: %m", conn->path);
- conn->fd = -1;
- return -1;
- }
-}
+++ /dev/null
-#ifndef STATS_CONNECTION_H
-#define STATS_CONNECTION_H
-
-struct stats_connection *stats_connection_create(const char *path);
-void stats_connection_ref(struct stats_connection *conn);
-void stats_connection_unref(struct stats_connection **conn);
-
-/* Returns 0 on success, -1 on failure. */
-int stats_connection_send(struct stats_connection *conn, const string_t *str);
-
-#endif
+++ /dev/null
-/* Copyright (c) 2011-2018 Dovecot authors, see the included COPYING file */
-
-#include "lib.h"
-#include "str.h"
-#include "time-util.h"
-#include "stats-parser.h"
-
-#define USECS_PER_SEC 1000000
-
-static bool stats_diff_timeval(struct timeval *dest,
- const struct timeval *src1,
- const struct timeval *src2)
-{
- long long diff_usecs;
-
- diff_usecs = timeval_diff_usecs(src2, src1);
- if (diff_usecs < 0)
- return FALSE;
- dest->tv_sec = diff_usecs / USECS_PER_SEC;
- dest->tv_usec = diff_usecs % USECS_PER_SEC;
- return TRUE;
-}
-
-static bool
-stats_diff_uint32(uint32_t *dest, const uint32_t *src1, const uint32_t *src2)
-{
- if (*src1 > *src2)
- return FALSE;
- *dest = *src2 - *src1;
- return TRUE;
-}
-
-static bool
-stats_diff_uint64(uint64_t *dest, const uint64_t *src1, const uint64_t *src2)
-{
- if (*src1 > *src2)
- return FALSE;
- *dest = *src2 - *src1;
- return TRUE;
-}
-
-bool stats_parser_diff(const struct stats_parser_field *fields,
- unsigned int fields_count,
- const struct stats *stats1, const struct stats *stats2,
- struct stats *diff_stats_r, const char **error_r)
-{
- unsigned int i;
-
- for (i = 0; i < fields_count; i++) {
- unsigned int offset = fields[i].offset;
- void *dest = PTR_OFFSET(diff_stats_r, offset);
- const void *src1 = CONST_PTR_OFFSET(stats1, offset);
- const void *src2 = CONST_PTR_OFFSET(stats2, offset);
-
- switch (fields[i].type) {
- case STATS_PARSER_TYPE_UINT:
- switch (fields[i].size) {
- case sizeof(uint32_t):
- if (!stats_diff_uint32(dest, src1, src2)) {
- *error_r = t_strdup_printf("%s %u < %u",
- fields[i].name,
- *(const uint32_t *)src2,
- *(const uint32_t *)src1);
- return FALSE;
- }
- break;
- case sizeof(uint64_t):
- if (!stats_diff_uint64(dest, src1, src2)) {
- const uint64_t *n1 = src1, *n2 = src2;
-
- *error_r = t_strdup_printf("%s %"PRIu64" < %"PRIu64,
- fields[i].name, *n2, *n1);
- return FALSE;
- }
- break;
- default:
- i_unreached();
- }
- break;
- case STATS_PARSER_TYPE_TIMEVAL:
- if (!stats_diff_timeval(dest, src1, src2)) {
- const struct timeval *tv1 = src1, *tv2 = src2;
-
- *error_r = t_strdup_printf("%s %ld.%d < %ld.%d",
- fields[i].name,
- (long)tv2->tv_sec, (int)tv2->tv_usec,
- (long)tv1->tv_sec, (int)tv1->tv_usec);
- return FALSE;
- }
- break;
- }
- }
- return TRUE;
-}
-
-static void stats_timeval_add(struct timeval *dest, const struct timeval *src)
-{
- dest->tv_sec += src->tv_sec;
- dest->tv_usec += src->tv_usec;
- if (dest->tv_usec > USECS_PER_SEC) {
- dest->tv_usec -= USECS_PER_SEC;
- dest->tv_sec++;
- }
-}
-
-void stats_parser_add(const struct stats_parser_field *fields,
- unsigned int fields_count,
- struct stats *dest, const struct stats *src)
-{
- unsigned int i;
-
- for (i = 0; i < fields_count; i++) {
- unsigned int offset = fields[i].offset;
- void *f_dest = PTR_OFFSET(dest, offset);
- const void *f_src = CONST_PTR_OFFSET(src, offset);
-
- switch (fields[i].type) {
- case STATS_PARSER_TYPE_UINT:
- switch (fields[i].size) {
- case sizeof(uint32_t): {
- uint32_t *n_dest = f_dest;
- const uint32_t *n_src = f_src;
-
- *n_dest += *n_src;
- break;
- }
- case sizeof(uint64_t): {
- uint64_t *n_dest = f_dest;
- const uint64_t *n_src = f_src;
-
- *n_dest += *n_src;
- break;
- }
- default:
- i_unreached();
- }
- break;
- case STATS_PARSER_TYPE_TIMEVAL:
- stats_timeval_add(f_dest, f_src);
- break;
- }
- }
-}
-
-void stats_parser_value(string_t *str,
- const struct stats_parser_field *field,
- const void *data)
-{
- const void *ptr = CONST_PTR_OFFSET(data, field->offset);
-
- switch (field->type) {
- case STATS_PARSER_TYPE_UINT:
- switch (field->size) {
- case sizeof(uint32_t): {
- const uint32_t *n = ptr;
-
- str_printfa(str, "%u", *n);
- break;
- }
- case sizeof(uint64_t): {
- const uint64_t *n = ptr;
-
- str_printfa(str, "%"PRIu64, *n);
- break;
- }
- default:
- i_unreached();
- }
- break;
- case STATS_PARSER_TYPE_TIMEVAL: {
- const struct timeval *tv = ptr;
-
- str_printfa(str, "%"PRIdTIME_T".%u",
- tv->tv_sec, (unsigned int)tv->tv_usec);
- break;
- }
- }
-}
+++ /dev/null
-#ifndef STATS_PARSER_H
-#define STATS_PARSER_H
-
-struct stats;
-
-enum stats_parser_type {
- STATS_PARSER_TYPE_UINT,
- STATS_PARSER_TYPE_TIMEVAL
-};
-
-struct stats_parser_field {
- const char *name;
- unsigned int offset;
- unsigned int size;
- enum stats_parser_type type;
-};
-
-bool stats_parser_diff(const struct stats_parser_field *fields,
- unsigned int fields_count,
- const struct stats *stats1, const struct stats *stats2,
- struct stats *diff_stats_r, const char **error_r);
-void stats_parser_add(const struct stats_parser_field *fields,
- unsigned int fields_count,
- struct stats *dest, const struct stats *src);
-void stats_parser_value(string_t *str,
- const struct stats_parser_field *field,
- const void *data);
-
-#endif
+++ /dev/null
-/* Copyright (c) 2015-2018 Dovecot authors, see the included COPYING file */
-
-#include "lib.h"
-#include "array.h"
-#include "stats.h"
-
-struct stats_item {
- struct stats_vfuncs v;
- size_t pos;
-};
-
-static ARRAY(struct stats_item *) stats_items = ARRAY_INIT;
-static unsigned int stats_total_size = 0;
-static bool stats_allocated = FALSE;
-
-struct stats_item *stats_register(const struct stats_vfuncs *vfuncs)
-{
- struct stats_item *item;
-
- if (stats_allocated)
- i_panic("stats_register() called after stats_alloc_size() was already called - this will break existing allocations");
-
- if (!array_is_created(&stats_items))
- i_array_init(&stats_items, 8);
-
- item = i_new(struct stats_item, 1);
- item->v = *vfuncs;
- item->pos = stats_total_size;
- array_push_back(&stats_items, &item);
-
- stats_total_size += vfuncs->alloc_size();
- return item;
-}
-
-static bool stats_item_find(struct stats_item *item, unsigned int *idx_r)
-{
- struct stats_item *const *itemp;
-
- array_foreach(&stats_items, itemp) {
- if (*itemp == item) {
- *idx_r = array_foreach_idx(&stats_items, itemp);
- return TRUE;
- }
- }
- return FALSE;
-}
-
-static struct stats_item *stats_item_find_by_name(const char *name)
-{
- struct stats_item *item;
-
- array_foreach_elem(&stats_items, item) {
- if (strcmp(item->v.short_name, name) == 0)
- return item;
- }
- return NULL;
-}
-
-void stats_unregister(struct stats_item **_item)
-{
- struct stats_item *item = *_item;
- unsigned int idx;
-
- *_item = NULL;
-
- if (!stats_item_find(item, &idx))
- i_unreached();
- array_delete(&stats_items, idx, 1);
-
- i_free(item);
- if (array_count(&stats_items) == 0) {
- array_free(&stats_items);
- /* all stats should have been freed by now. allow
- re-registering and using stats. */
- stats_allocated = FALSE;
- }
-}
-
-struct stats *stats_alloc(pool_t pool)
-{
- return p_malloc(pool, stats_alloc_size());
-}
-
-size_t stats_alloc_size(void)
-{
- stats_allocated = TRUE;
- return stats_total_size;
-}
-
-void stats_copy(struct stats *dest, const struct stats *src)
-{
- memcpy(dest, src, stats_total_size);
-}
-
-unsigned int stats_field_count(void)
-{
- struct stats_item *item;
- unsigned int count = 0;
-
- array_foreach_elem(&stats_items, item)
- count += item->v.field_count();
- return count;
-}
-
-const char *stats_field_name(unsigned int n)
-{
- struct stats_item *item;
- unsigned int i = 0, count;
-
- array_foreach_elem(&stats_items, item) {
- count = item->v.field_count();
- if (i + count > n)
- return item->v.field_name(n - i);
- i += count;
- }
- i_unreached();
-}
-
-void stats_field_value(string_t *str, const struct stats *stats,
- unsigned int n)
-{
- struct stats_item *item;
- unsigned int i = 0, count;
-
- array_foreach_elem(&stats_items, item) {
- count = item->v.field_count();
- if (i + count > n) {
- const void *item_stats =
- CONST_PTR_OFFSET(stats, item->pos);
- item->v.field_value(str, item_stats, n - i);
- return;
- }
- i += count;
- }
- i_unreached();
-}
-
-bool stats_diff(const struct stats *stats1, const struct stats *stats2,
- struct stats *diff_stats_r, const char **error_r)
-{
- struct stats_item *item;
- bool ret = TRUE;
-
- array_foreach_elem(&stats_items, item) {
- if (!item->v.diff(CONST_PTR_OFFSET(stats1, item->pos),
- CONST_PTR_OFFSET(stats2, item->pos),
- PTR_OFFSET(diff_stats_r, item->pos),
- error_r))
- ret = FALSE;
- }
- return ret;
-}
-
-void stats_add(struct stats *dest, const struct stats *src)
-{
- struct stats_item *item;
-
- array_foreach_elem(&stats_items, item) {
- item->v.add(PTR_OFFSET(dest, item->pos),
- CONST_PTR_OFFSET(src, item->pos));
- }
-}
-
-bool stats_have_changed(const struct stats *prev, const struct stats *cur)
-{
- struct stats_item *item;
-
- array_foreach_elem(&stats_items, item) {
- if (item->v.have_changed(CONST_PTR_OFFSET(prev, item->pos),
- CONST_PTR_OFFSET(cur, item->pos)))
- return TRUE;
- }
- return FALSE;
-}
-
-void stats_export(buffer_t *buf, const struct stats *stats)
-{
- struct stats_item *item;
-
- array_foreach_elem(&stats_items, item) {
- buffer_append(buf, item->v.short_name,
- strlen(item->v.short_name)+1);
- item->v.export(buf, CONST_PTR_OFFSET(stats, item->pos));
- }
-}
-
-bool stats_import(const unsigned char *data, size_t size,
- const struct stats *old_stats, struct stats *stats,
- const char **error_r)
-{
- struct stats_item *item;
- const unsigned char *p;
- size_t pos;
-
- memcpy(stats, old_stats, stats_total_size);
- while (size > 0) {
- const char *next_name = (const void *)data;
-
- p = memchr(data, '\0', size);
- if (p == NULL) {
- *error_r = "Expected name, but NUL is missing";
- return FALSE;
- }
- item = stats_item_find_by_name(next_name);
- if (item == NULL) {
- *error_r = t_strdup_printf("Unknown stats name: '%s'", next_name);
- return FALSE;
- }
- size -= (p+1) - data;
- data = p+1;
- if (!item->v.import(data, size, &pos,
- PTR_OFFSET(stats, item->pos), error_r))
- return FALSE;
- i_assert(pos <= size);
- data += pos;
- size -= pos;
- }
- return TRUE;
-}
-
-void *stats_fill_ptr(struct stats *stats, struct stats_item *item)
-{
- return PTR_OFFSET(stats, item->pos);
-}
-
-void stats_reset(struct stats *stats)
-{
- memset(stats, 0, stats_total_size);
-}
+++ /dev/null
-#ifndef STATS_H
-#define STATS_H
-
-struct stats;
-struct stats_item;
-
-struct stats_vfuncs {
- const char *short_name;
-
- size_t (*alloc_size)(void);
- unsigned int (*field_count)(void);
- const char *(*field_name)(unsigned int n);
- void (*field_value)(string_t *str, const struct stats *stats,
- unsigned int n);
-
- bool (*diff)(const struct stats *stats1, const struct stats *stats2,
- struct stats *diff_stats_r, const char **error_r);
- void (*add)(struct stats *dest, const struct stats *src);
- bool (*have_changed)(const struct stats *prev, const struct stats *cur);
-
- void (*export)(buffer_t *buf, const struct stats *stats);
- bool (*import)(const unsigned char *data, size_t size, size_t *pos_r,
- struct stats *stats, const char **error_r);
-};
-
-struct stats_item *stats_register(const struct stats_vfuncs *vfuncs);
-void stats_unregister(struct stats_item **item);
-
-/* Allocate struct stats from a given pool. */
-struct stats *stats_alloc(pool_t pool);
-/* Returns the number of bytes allocated to stats. */
-size_t stats_alloc_size(void);
-/* Copy all stats from src to dest. */
-void stats_copy(struct stats *dest, const struct stats *src);
-
-/* Returns the number of stats fields. */
-unsigned int stats_field_count(void);
-/* Returns the name of a stats field (exported to doveadm). */
-const char *stats_field_name(unsigned int n);
-/* Returns the value of a stats field as a string (exported to doveadm). */
-void stats_field_value(string_t *str, const struct stats *stats,
- unsigned int n);
-
-/* Return diff_stats_r->field = stats2->field - stats1->field.
- diff1 is supposed to have smaller values than diff2. Returns TRUE if this
- is so, FALSE if not */
-bool stats_diff(const struct stats *stats1, const struct stats *stats2,
- struct stats *diff_stats_r, const char **error_r);
-/* dest->field += src->field */
-void stats_add(struct stats *dest, const struct stats *src);
-/* Returns TRUE if any fields have changed in cur since prev in a way that
- a plugin should send the updated statistics to the stats process. Not all
- fields necessarily require sending an update. */
-bool stats_have_changed(const struct stats *prev, const struct stats *cur);
-
-/* Export stats into a buffer in binary format. */
-void stats_export(buffer_t *buf, const struct stats *stats);
-/* Import stats from a buffer. The buffer doesn't need to contain an update to
- all the stats items - old_stats are used for that item in such case.
- Currently it's not allowed to have unknown items in the buffer. */
-bool stats_import(const unsigned char *data, size_t size,
- const struct stats *old_stats, struct stats *stats,
- const char **error_r);
-/* Return a pointer to stats where the specified item starts. The returned
- pointer can be used to fill up the item-specific stats (up to its
- alloc_size() number of bytes). */
-void *stats_fill_ptr(struct stats *stats, struct stats_item *item);
-
-void stats_reset(struct stats *stats);
-
-#endif
+++ /dev/null
-old_stats_moduledir = $(moduledir)/old-stats
-pkglibexecdir = $(libexecdir)/dovecot
-
-pkglibexec_PROGRAMS = old-stats
-
-AM_CPPFLAGS = \
- -DSTATS_MODULE_DIR=\""$(old_stats_moduledir)"\" \
- -I$(top_srcdir)/src/lib \
- -I$(top_srcdir)/src/lib-settings \
- -I$(top_srcdir)/src/lib-master \
- -I$(top_srcdir)/src/lib-old-stats \
- $(BINARY_CFLAGS)
-
-old_stats_LDADD = $(LIBDOVECOT) \
- $(BINARY_LDFLAGS)
-
-old_stats_DEPENDENCIES = $(LIBDOVECOT_DEPS)
-
-old_stats_SOURCES = \
- client.c \
- client-export.c \
- client-reset.c \
- fifo-input-connection.c \
- global-memory.c \
- mail-command.c \
- mail-domain.c \
- mail-ip.c \
- mail-session.c \
- mail-stats.c \
- mail-user.c \
- main.c \
- stats-carbon.c \
- stats-settings.c
-
-noinst_HEADERS = \
- client.h \
- client-export.h \
- client-reset.h \
- fifo-input-connection.h \
- global-memory.h \
- mail-command.h \
- mail-domain.h \
- mail-ip.h \
- mail-session.h \
- mail-stats.h \
- mail-user.h \
- stats-carbon.h \
- stats-settings.h
+++ /dev/null
-/* Copyright (c) 2011-2018 Dovecot authors, see the included COPYING file */
-
-#include "lib.h"
-#include "net.h"
-#include "ostream.h"
-#include "str.h"
-#include "strescape.h"
-#include "wildcard-match.h"
-#include "mail-stats.h"
-#include "mail-command.h"
-#include "mail-session.h"
-#include "mail-user.h"
-#include "mail-domain.h"
-#include "mail-ip.h"
-#include "client.h"
-#include "client-export.h"
-
-enum mail_export_level {
- MAIL_EXPORT_LEVEL_COMMAND,
- MAIL_EXPORT_LEVEL_SESSION,
- MAIL_EXPORT_LEVEL_USER,
- MAIL_EXPORT_LEVEL_DOMAIN,
- MAIL_EXPORT_LEVEL_IP,
- MAIL_EXPORT_LEVEL_GLOBAL
-};
-static const char *mail_export_level_names[] = {
- "command", "session", "user", "domain", "ip", "global"
-};
-
-struct mail_export_filter {
- const char *user, *domain, *session;
- struct ip_addr ip;
- unsigned int ip_bits;
- time_t since;
- bool connected;
-};
-
-struct client_export_cmd {
- enum mail_export_level level;
- struct mail_export_filter filter;
- string_t *str;
- int (*export_iter)(struct client *client);
- bool header_sent;
-};
-
-static int
-mail_export_level_parse(const char *str, enum mail_export_level *level_r)
-{
- unsigned int i;
-
- for (i = 0; i < N_ELEMENTS(mail_export_level_names); i++) {
- if (strcmp(mail_export_level_names[i], str) == 0) {
- *level_r = (enum mail_export_level)i;
- return 0;
- }
- }
- return -1;
-}
-
-static int
-mail_export_parse_filter(const char *const *args, pool_t pool,
- struct mail_export_filter *filter_r,
- const char **error_r)
-{
- unsigned long l;
-
- /* filters:
- user=<wildcard> | domain=<wildcard> | session=<str>
- ip=<ip>[/<mask>]
- since=<timestamp>
- connected
- */
- i_zero(filter_r);
- for (; *args != NULL; args++) {
- if (str_begins(*args, "user="))
- filter_r->user = p_strdup(pool, *args + 5);
- else if (str_begins(*args, "domain="))
- filter_r->domain = p_strdup(pool, *args + 7);
- else if (str_begins(*args, "session="))
- filter_r->session = p_strdup(pool, *args + 8);
- else if (str_begins(*args, "ip=")) {
- if (net_parse_range(*args + 3, &filter_r->ip,
- &filter_r->ip_bits) < 0) {
- *error_r = "Invalid ip filter";
- return -1;
- }
- } else if (str_begins(*args, "since=")) {
- if (str_to_ulong(*args + 6, &l) < 0) {
- *error_r = "Invalid since filter";
- return -1;
- }
- filter_r->since = (time_t)l;
- } else if (strcmp(*args, "connected") == 0) {
- filter_r->connected = TRUE;
- }
- }
- return 0;
-}
-
-static void
-client_export_stats_headers(struct client *client)
-{
- unsigned int i, count = stats_field_count();
- string_t *str = t_str_new(128);
-
- i_assert(count > 0);
-
- str_append(str, stats_field_name(0));
- for (i = 1; i < count; i++) {
- str_append_c(str, '\t');
- str_append(str, stats_field_name(i));
- }
- str_append_c(str, '\n');
- o_stream_nsend(client->output, str_data(str), str_len(str));
-}
-
-static void
-client_export_stats(string_t *str, const struct stats *stats)
-{
- unsigned int i, count = stats_field_count();
-
- i_assert(count > 0);
-
- stats_field_value(str, stats, 0);
- for (i = 1; i < count; i++) {
- str_append_c(str, '\t');
- stats_field_value(str, stats, i);
- }
-}
-
-static bool
-mail_export_filter_match_session(const struct mail_export_filter *filter,
- const struct mail_session *session)
-{
- if (filter->connected && session->disconnected)
- return FALSE;
- if (filter->since > session->last_update.tv_sec)
- return FALSE;
- if (filter->session != NULL &&
- strcmp(session->id, filter->session) != 0)
- return FALSE;
- if (filter->user != NULL &&
- !wildcard_match(session->user->name, filter->user))
- return FALSE;
- if (filter->domain != NULL &&
- !wildcard_match(session->user->domain->name, filter->domain))
- return FALSE;
- if (filter->ip_bits > 0 &&
- !net_is_in_network(&session->ip->ip, &filter->ip, filter->ip_bits))
- return FALSE;
- return TRUE;
-}
-
-static bool
-mail_export_filter_match_user_common(const struct mail_export_filter *filter,
- const struct mail_user *user)
-{
- struct mail_session *s;
- bool connected = FALSE, ip_ok = FALSE;
-
- if (filter->user != NULL &&
- !wildcard_match(user->name, filter->user))
- return FALSE;
-
- if (filter->connected || filter->ip_bits > 0) {
- for (s = user->sessions; s != NULL; s = s->user_next) {
- if (!s->disconnected)
- connected = TRUE;
- if (filter->ip_bits > 0 &&
- net_is_in_network(&s->ip->ip, &filter->ip,
- filter->ip_bits))
- ip_ok = TRUE;
-
- }
- if (filter->connected && !connected)
- return FALSE;
- if (filter->ip_bits > 0 && !ip_ok)
- return FALSE;
- }
- return TRUE;
-}
-
-static bool
-mail_export_filter_match_user(const struct mail_export_filter *filter,
- const struct mail_user *user)
-{
- if (filter->since > user->last_update.tv_sec)
- return FALSE;
- if (filter->domain != NULL &&
- !wildcard_match(user->domain->name, filter->domain))
- return FALSE;
- return mail_export_filter_match_user_common(filter, user);
-}
-
-static bool
-mail_export_filter_match_domain(const struct mail_export_filter *filter,
- const struct mail_domain *domain)
-{
- struct mail_user *user;
-
- if (filter->since > domain->last_update.tv_sec)
- return FALSE;
- if (filter->domain != NULL &&
- !wildcard_match(domain->name, filter->domain))
- return FALSE;
-
- if (filter->user != NULL || filter->connected || filter->ip_bits > 0) {
- for (user = domain->users; user != NULL; user = user->domain_next) {
- if (mail_export_filter_match_user_common(filter, user))
- break;
- }
- if (user == NULL)
- return FALSE;
- }
- return TRUE;
-}
-
-static bool
-mail_export_filter_match_ip(const struct mail_export_filter *filter,
- const struct mail_ip *ip)
-{
- struct mail_session *s;
- bool connected = FALSE, user_ok = FALSE, domain_ok = FALSE;
-
- if (filter->connected || filter->ip_bits > 0) {
- for (s = ip->sessions; s != NULL; s = s->ip_next) {
- if (!s->disconnected)
- connected = TRUE;
- if (filter->user != NULL &&
- wildcard_match(s->user->name, filter->user))
- user_ok = TRUE;
- if (filter->domain != NULL &&
- wildcard_match(s->user->domain->name, filter->domain))
- domain_ok = TRUE;
- }
- if (filter->connected && !connected)
- return FALSE;
- if (filter->user != NULL && !user_ok)
- return FALSE;
- if (filter->domain != NULL && !domain_ok)
- return FALSE;
- }
- if (filter->since > ip->last_update.tv_sec)
- return FALSE;
- if (filter->ip_bits > 0 &&
- !net_is_in_network(&ip->ip, &filter->ip, filter->ip_bits))
- return FALSE;
- return TRUE;
-}
-
-static void client_export_timeval(string_t *str, const struct timeval *tv)
-{
- str_printfa(str, "\t%ld.%06u", (long)tv->tv_sec,
- (unsigned int)tv->tv_usec);
-}
-
-static int client_export_iter_command(struct client *client)
-{
- struct client_export_cmd *cmd = client->cmd_export;
- struct mail_command *command = client->mail_cmd_iter;
-
- i_assert(cmd->level == MAIL_EXPORT_LEVEL_COMMAND);
- mail_command_unref(&client->mail_cmd_iter);
-
- if (!cmd->header_sent) {
- o_stream_nsend_str(client->output,
- "cmd\targs\tsession\tuser\tlast_update\t");
- client_export_stats_headers(client);
- cmd->header_sent = TRUE;
- }
-
- for (; command != NULL; command = command->stable_next) {
- if (client_is_busy(client))
- break;
- if (!mail_export_filter_match_session(&cmd->filter,
- command->session))
- continue;
-
- str_truncate(cmd->str, 0);
- str_append_tabescaped(cmd->str, command->name);
- str_append_c(cmd->str, '\t');
- str_append_tabescaped(cmd->str, command->args);
- str_append_c(cmd->str, '\t');
- str_append(cmd->str, command->session->id);
- str_append_c(cmd->str, '\t');
- str_append_tabescaped(cmd->str,
- command->session->user->name);
- client_export_timeval(cmd->str, &command->last_update);
- str_append_c(cmd->str, '\t');
- client_export_stats(cmd->str, command->stats);
- str_append_c(cmd->str, '\n');
- o_stream_nsend(client->output, str_data(cmd->str),
- str_len(cmd->str));
- }
-
- if (command != NULL) {
- client->mail_cmd_iter = command;
- mail_command_ref(command);
- return 0;
- }
- return 1;
-}
-
-static int client_export_iter_session(struct client *client)
-{
- struct client_export_cmd *cmd = client->cmd_export;
- struct mail_session *session = client->mail_session_iter;
-
- i_assert(cmd->level == MAIL_EXPORT_LEVEL_SESSION);
- mail_session_unref(&client->mail_session_iter);
-
- if (!cmd->header_sent) {
- o_stream_nsend_str(client->output,
- "session\tuser\tip\tservice\tpid\tconnected"
- "\tlast_update\tnum_cmds\t");
- client_export_stats_headers(client);
- cmd->header_sent = TRUE;
- }
-
- for (; session != NULL; session = session->stable_next) {
- if (client_is_busy(client))
- break;
- if (!mail_export_filter_match_session(&cmd->filter, session))
- continue;
-
- str_truncate(cmd->str, 0);
- str_append(cmd->str, session->id);
- str_append_c(cmd->str, '\t');
- str_append_tabescaped(cmd->str, session->user->name);
- str_append_c(cmd->str, '\t');
- if (session->ip != NULL) T_BEGIN {
- str_append(cmd->str, net_ip2addr(&session->ip->ip));
- } T_END;
- str_append_c(cmd->str, '\t');
- str_append_tabescaped(cmd->str, session->service);
- str_printfa(cmd->str, "\t%lu", (unsigned long)session->pid);
- str_printfa(cmd->str, "\t%d", !session->disconnected);
- client_export_timeval(cmd->str, &session->last_update);
- str_printfa(cmd->str, "\t%u\t", session->num_cmds);
- client_export_stats(cmd->str, session->stats);
- str_append_c(cmd->str, '\n');
- o_stream_nsend(client->output, str_data(cmd->str),
- str_len(cmd->str));
- }
-
- if (session != NULL) {
- client->mail_session_iter = session;
- mail_session_ref(session);
- return 0;
- }
- return 1;
-}
-
-static int client_export_iter_user(struct client *client)
-{
- struct client_export_cmd *cmd = client->cmd_export;
- struct mail_user *user = client->mail_user_iter;
-
- i_assert(cmd->level == MAIL_EXPORT_LEVEL_USER);
- mail_user_unref(&client->mail_user_iter);
-
- if (!cmd->header_sent) {
- o_stream_nsend_str(client->output,
- "user\treset_timestamp\tlast_update"
- "\tnum_logins\tnum_cmds\t");
- client_export_stats_headers(client);
- cmd->header_sent = TRUE;
- }
-
- for (; user != NULL; user = user->stable_next) {
- if (client_is_busy(client))
- break;
- if (!mail_export_filter_match_user(&cmd->filter, user))
- continue;
-
- str_truncate(cmd->str, 0);
- str_append_tabescaped(cmd->str, user->name);
- str_printfa(cmd->str, "\t%ld", (long)user->reset_timestamp);
- client_export_timeval(cmd->str, &user->last_update);
- str_printfa(cmd->str, "\t%u\t%u\t",
- user->num_logins, user->num_cmds);
- client_export_stats(cmd->str, user->stats);
- str_append_c(cmd->str, '\n');
- o_stream_nsend(client->output, str_data(cmd->str),
- str_len(cmd->str));
- }
-
- if (user != NULL) {
- client->mail_user_iter = user;
- mail_user_ref(user);
- return 0;
- }
- return 1;
-}
-
-static int client_export_iter_domain(struct client *client)
-{
- struct client_export_cmd *cmd = client->cmd_export;
- struct mail_domain *domain = client->mail_domain_iter;
-
- i_assert(cmd->level == MAIL_EXPORT_LEVEL_DOMAIN);
- mail_domain_unref(&client->mail_domain_iter);
-
- if (!cmd->header_sent) {
- o_stream_nsend_str(client->output,
- "domain\treset_timestamp\tlast_update"
- "\tnum_logins\tnum_cmds\tnum_connected_sessions\t");
- client_export_stats_headers(client);
- cmd->header_sent = TRUE;
- }
-
- for (; domain != NULL; domain = domain->stable_next) {
- if (client_is_busy(client))
- break;
- if (!mail_export_filter_match_domain(&cmd->filter, domain))
- continue;
-
- str_truncate(cmd->str, 0);
- str_append_tabescaped(cmd->str, domain->name);
- str_printfa(cmd->str, "\t%ld", (long)domain->reset_timestamp);
- client_export_timeval(cmd->str, &domain->last_update);
- str_printfa(cmd->str, "\t%u\t%u\t%u\t",
- domain->num_logins, domain->num_cmds,
- domain->num_connected_sessions);
- client_export_stats(cmd->str, domain->stats);
- str_append_c(cmd->str, '\n');
- o_stream_nsend(client->output, str_data(cmd->str),
- str_len(cmd->str));
- }
-
- if (domain != NULL) {
- client->mail_domain_iter = domain;
- mail_domain_ref(domain);
- return 0;
- }
- return 1;
-}
-
-static int client_export_iter_ip(struct client *client)
-{
- struct client_export_cmd *cmd = client->cmd_export;
- struct mail_ip *ip = client->mail_ip_iter;
-
- i_assert(cmd->level == MAIL_EXPORT_LEVEL_IP);
- mail_ip_unref(&client->mail_ip_iter);
-
- if (!cmd->header_sent) {
- o_stream_nsend_str(client->output,
- "ip\treset_timestamp\tlast_update"
- "\tnum_logins\tnum_cmds\tnum_connected_sessions\t");
- client_export_stats_headers(client);
- cmd->header_sent = TRUE;
- }
-
- for (; ip != NULL; ip = ip->stable_next) {
- if (client_is_busy(client))
- break;
- if (!mail_export_filter_match_ip(&cmd->filter, ip))
- continue;
-
- str_truncate(cmd->str, 0);
- T_BEGIN {
- str_append(cmd->str, net_ip2addr(&ip->ip));
- } T_END;
- str_printfa(cmd->str, "\t%ld", (long)ip->reset_timestamp);
- client_export_timeval(cmd->str, &ip->last_update);
- str_printfa(cmd->str, "\t%u\t%u\t%u\t",
- ip->num_logins, ip->num_cmds, ip->num_connected_sessions);
- client_export_stats(cmd->str, ip->stats);
- str_append_c(cmd->str, '\n');
- o_stream_nsend(client->output, str_data(cmd->str),
- str_len(cmd->str));
- }
-
- if (ip != NULL) {
- client->mail_ip_iter = ip;
- mail_ip_ref(ip);
- return 0;
- }
- return 1;
-}
-
-static int client_export_iter_global(struct client *client)
-{
- struct client_export_cmd *cmd = client->cmd_export;
- struct mail_global *g = &mail_global_stats;
-
- i_assert(cmd->level == MAIL_EXPORT_LEVEL_GLOBAL);
-
- if (!cmd->header_sent) {
- o_stream_nsend_str(client->output,
- "reset_timestamp\tlast_update"
- "\tnum_logins\tnum_cmds\tnum_connected_sessions\t");
- client_export_stats_headers(client);
- cmd->header_sent = TRUE;
- }
-
- str_truncate(cmd->str, 0);
- str_printfa(cmd->str, "%ld", (long)g->reset_timestamp);
- client_export_timeval(cmd->str, &g->last_update);
- str_printfa(cmd->str, "\t%u\t%u\t%u\t",
- g->num_logins, g->num_cmds, g->num_connected_sessions);
- client_export_stats(cmd->str, g->stats);
- str_append_c(cmd->str, '\n');
- o_stream_nsend(client->output, str_data(cmd->str),
- str_len(cmd->str));
- return 1;
-}
-
-static int client_export_more(struct client *client)
-{
- if (client->cmd_export->export_iter(client) == 0)
- return 0;
- o_stream_nsend_str(client->output, "\n");
- return 1;
-}
-
-static bool client_export_iter_init(struct client *client)
-{
- struct client_export_cmd *cmd = client->cmd_export;
-
- if (cmd->filter.user != NULL && strchr(cmd->filter.user, '*') == NULL &&
- (cmd->level == MAIL_EXPORT_LEVEL_USER ||
- cmd->level == MAIL_EXPORT_LEVEL_SESSION)) {
- /* exact user */
- struct mail_user *user = mail_user_lookup(cmd->filter.user);
- if (user == NULL)
- return FALSE;
- if (cmd->level == MAIL_EXPORT_LEVEL_SESSION) {
- client->mail_session_iter = user->sessions;
- if (client->mail_session_iter == NULL)
- return FALSE;
- mail_session_ref(client->mail_session_iter);
- cmd->export_iter = client_export_iter_session;
- } else {
- client->mail_user_iter = user;
- mail_user_ref(user);
- cmd->export_iter = client_export_iter_user;
- }
- return TRUE;
- }
- if (cmd->filter.ip_bits == IPADDR_BITS(&cmd->filter.ip) &&
- (cmd->level == MAIL_EXPORT_LEVEL_IP ||
- cmd->level == MAIL_EXPORT_LEVEL_SESSION)) {
- /* exact IP address */
- struct mail_ip *ip = mail_ip_lookup(&cmd->filter.ip);
- if (ip == NULL)
- return FALSE;
- if (cmd->level == MAIL_EXPORT_LEVEL_SESSION) {
- client->mail_session_iter = ip->sessions;
- if (client->mail_session_iter == NULL)
- return FALSE;
- mail_session_ref(client->mail_session_iter);
- cmd->export_iter = client_export_iter_session;
- } else {
- client->mail_ip_iter = ip;
- mail_ip_ref(ip);
- cmd->export_iter = client_export_iter_ip;
- }
- return TRUE;
- }
- if (cmd->filter.domain != NULL &&
- strchr(cmd->filter.domain, '*') == NULL &&
- (cmd->level == MAIL_EXPORT_LEVEL_DOMAIN ||
- cmd->level == MAIL_EXPORT_LEVEL_USER)) {
- /* exact domain */
- struct mail_domain *domain =
- mail_domain_lookup(cmd->filter.domain);
- if (domain == NULL)
- return FALSE;
- if (cmd->level == MAIL_EXPORT_LEVEL_USER) {
- client->mail_user_iter = domain->users;
- mail_user_ref(client->mail_user_iter);
- cmd->export_iter = client_export_iter_user;
- } else {
- client->mail_domain_iter = domain;
- mail_domain_ref(domain);
- cmd->export_iter = client_export_iter_domain;
- }
- return TRUE;
- }
-
- switch (cmd->level) {
- case MAIL_EXPORT_LEVEL_COMMAND:
- client->mail_cmd_iter = stable_mail_commands_head;
- if (client->mail_cmd_iter == NULL)
- return FALSE;
- mail_command_ref(client->mail_cmd_iter);
- cmd->export_iter = client_export_iter_command;
- break;
- case MAIL_EXPORT_LEVEL_SESSION:
- client->mail_session_iter = stable_mail_sessions;
- if (client->mail_session_iter == NULL)
- return FALSE;
- mail_session_ref(client->mail_session_iter);
- cmd->export_iter = client_export_iter_session;
- break;
- case MAIL_EXPORT_LEVEL_USER:
- client->mail_user_iter = stable_mail_users;
- if (client->mail_user_iter == NULL)
- return FALSE;
- mail_user_ref(client->mail_user_iter);
- cmd->export_iter = client_export_iter_user;
- break;
- case MAIL_EXPORT_LEVEL_DOMAIN:
- client->mail_domain_iter = stable_mail_domains;
- if (client->mail_domain_iter == NULL)
- return FALSE;
- mail_domain_ref(client->mail_domain_iter);
- cmd->export_iter = client_export_iter_domain;
- break;
- case MAIL_EXPORT_LEVEL_IP:
- client->mail_ip_iter = stable_mail_ips;
- if (client->mail_ip_iter == NULL)
- return FALSE;
- mail_ip_ref(client->mail_ip_iter);
- cmd->export_iter = client_export_iter_ip;
- break;
- case MAIL_EXPORT_LEVEL_GLOBAL:
- cmd->export_iter = client_export_iter_global;
- break;
- }
- i_assert(cmd->export_iter != NULL);
- return TRUE;
-}
-
-int client_export(struct client *client, const char *const *args,
- const char **error_r)
-{
- const char *level_str = args[0];
- struct client_export_cmd *cmd;
-
- p_clear(client->cmd_pool);
- cmd = p_new(client->cmd_pool, struct client_export_cmd, 1);
- cmd->str = str_new(client->cmd_pool, 256);
-
- if (level_str == NULL) {
- *error_r = "Missing level parameter";
- return -1;
- }
- if (mail_export_level_parse(level_str, &cmd->level) < 0) {
- *error_r = "Invalid level";
- return -1;
- }
- if (mail_export_parse_filter(args + 1, client->cmd_pool,
- &cmd->filter, error_r) < 0)
- return -1;
-
- client->cmd_export = cmd;
- if (!client_export_iter_init(client)) {
- /* nothing to export */
- o_stream_nsend_str(client->output, "\n");
- return 1;
- }
- client->cmd_more = client_export_more;
- return client_export_more(client);
-}
+++ /dev/null
-#ifndef CLIENT_EXPORT_H
-#define CLIENT_EXPORT_H
-
-struct client;
-
-int client_export(struct client *client, const char *const *args,
- const char **error_r);
-
-#endif
+++ /dev/null
-/* Copyright (c) 2016-2018 Dovecot authors, see the included COPYING file */
-
-#include "lib.h"
-#include "ostream.h"
-#include "strescape.h"
-#include "mail-stats.h"
-#include "client.h"
-#include "client-reset.h"
-
-int client_stats_reset(struct client *client, const char *const *args ATTR_UNUSED,
- const char **error_r ATTR_UNUSED)
-{
- struct mail_global *g = &mail_global_stats;
- stats_reset(g->stats);
- g->num_logins = 0;
- g->num_cmds = 0;
- g->reset_timestamp = ioloop_time;
- i_zero(&g->last_update);
- o_stream_nsend_str(client->output, "OK\n");
- return 0;
-}
+++ /dev/null
-#ifndef CLIENT_RESET_H
-#define CLIENT_RESET_H
-
-struct client;
-
-int client_stats_reset(struct client *client, const char *const *args,
- const char **error_r);
-
-#endif
+++ /dev/null
-/* Copyright (c) 2011-2018 Dovecot authors, see the included COPYING file */
-
-#include "lib.h"
-#include "llist.h"
-#include "ioloop.h"
-#include "istream.h"
-#include "ostream.h"
-#include "strescape.h"
-#include "master-service.h"
-#include "mail-command.h"
-#include "mail-session.h"
-#include "mail-user.h"
-#include "mail-domain.h"
-#include "mail-ip.h"
-#include "client-export.h"
-#include "client-reset.h"
-#include "client.h"
-
-#include <unistd.h>
-
-#define CLIENT_MAX_SIMULTANEOUS_ITER_COUNT 1000
-#define MAX_INBUF_SIZE 1024
-#define OUTBUF_THROTTLE_SIZE (1024*64)
-
-static struct client *clients;
-
-bool client_is_busy(struct client *client)
-{
- client->iter_count++;
- if (client->iter_count % CLIENT_MAX_SIMULTANEOUS_ITER_COUNT == 0)
- return TRUE;
- if (o_stream_get_buffer_used_size(client->output) < OUTBUF_THROTTLE_SIZE)
- return FALSE;
- if (o_stream_flush(client->output) < 0)
- return TRUE;
- return o_stream_get_buffer_used_size(client->output) >= OUTBUF_THROTTLE_SIZE;
-}
-
-static int
-client_handle_request(struct client *client, const char *const *args,
- const char **error_r)
-{
- const char *cmd = args[0];
-
- if (cmd == NULL) {
- *error_r = "Missing command";
- return -1;
- }
- args++;
-
- if (strcmp(cmd, "EXPORT") == 0)
- return client_export(client, args, error_r);
- if (strcmp(cmd, "RESET") == 0)
- return client_stats_reset(client, args, error_r);
-
- *error_r = "Unknown command";
- return -1;
-}
-
-static const char *const*
-client_read_next_line(struct client *client)
-{
- const char *line;
-
- line = i_stream_next_line(client->input);
- if (line == NULL)
- return NULL;
-
- return t_strsplit_tabescaped(line);
-}
-
-static void client_input(struct client *client)
-{
- const char *const *args, *error;
- int ret;
-
- timeout_remove(&client->to_pending);
-
- switch (i_stream_read(client->input)) {
- case -2:
- i_error("BUG: Stats client sent too much data");
- client_destroy(&client);
- return;
- case -1:
- client_destroy(&client);
- return;
- }
-
- o_stream_cork(client->output);
- while ((args = client_read_next_line(client)) != NULL) {
- ret = client_handle_request(client, args, &error);
- if (ret < 0) {
- i_error("Stats client input error: %s", error);
- client_destroy(&client);
- return;
- }
- if (ret == 0) {
- o_stream_set_flush_pending(client->output, TRUE);
- io_remove(&client->io);
- break;
- }
- client->cmd_more = NULL;
- }
- o_stream_uncork(client->output);
-}
-
-static int client_output(struct client *client)
-{
- int ret = 1;
-
- if (o_stream_flush(client->output) < 0) {
- client_destroy(&client);
- return 1;
- }
- if (client->cmd_more != NULL)
- ret = client->cmd_more(client);
-
- if (ret > 0) {
- client->cmd_more = NULL;
- if (client->io == NULL)
- client_enable_io(client);
- }
- return ret;
-}
-
-void client_enable_io(struct client *client)
-{
- i_assert(client->io == NULL);
-
- client->io = io_add(client->fd, IO_READ, client_input, client);
- if (client->to_pending == NULL)
- client->to_pending = timeout_add(0, client_input, client);
-}
-
-struct client *client_create(int fd)
-{
- struct client *client;
-
- client = i_new(struct client, 1);
- client->fd = fd;
- client->io = io_add(fd, IO_READ, client_input, client);
- client->input = i_stream_create_fd(fd, MAX_INBUF_SIZE);
- client->output = o_stream_create_fd(fd, SIZE_MAX);
- o_stream_set_no_error_handling(client->output, TRUE);
- o_stream_set_flush_callback(client->output, client_output, client);
- client->cmd_pool = pool_alloconly_create("cmd pool", 1024);
-
- DLLIST_PREPEND(&clients, client);
- return client;
-}
-
-static void client_unref_iters(struct client *client)
-{
- if (client->mail_cmd_iter != NULL)
- mail_command_unref(&client->mail_cmd_iter);
- if (client->mail_session_iter != NULL)
- mail_session_unref(&client->mail_session_iter);
- if (client->mail_user_iter != NULL)
- mail_user_unref(&client->mail_user_iter);
- if (client->mail_domain_iter != NULL)
- mail_domain_unref(&client->mail_domain_iter);
- if (client->mail_ip_iter != NULL)
- mail_ip_unref(&client->mail_ip_iter);
-}
-
-void client_destroy(struct client **_client)
-{
- struct client *client = *_client;
-
- *_client = NULL;
-
- DLLIST_REMOVE(&clients, client);
- io_remove(&client->io);
- i_stream_destroy(&client->input);
- o_stream_destroy(&client->output);
- if (close(client->fd) < 0)
- i_error("close(client) failed: %m");
-
- client_unref_iters(client);
- pool_unref(&client->cmd_pool);
- i_free(client);
-
- master_service_client_connection_destroyed(master_service);
-}
-
-void clients_destroy_all(void)
-{
- while (clients != NULL) {
- struct client *client = clients;
-
- client_destroy(&client);
- }
-}
+++ /dev/null
-#ifndef CLIENT_H
-#define CLIENT_H
-
-struct client {
- struct client *prev, *next;
-
- int fd;
- struct io *io;
- struct istream *input;
- struct ostream *output;
- struct timeout *to_pending;
-
- pool_t cmd_pool;
- struct client_export_cmd *cmd_export;
- int (*cmd_more)(struct client *client);
-
- /* command iterators. while non-NULL, they've increased the
- struct's refcount so it won't be deleted during iteration */
- unsigned int iter_count;
- struct mail_command *mail_cmd_iter;
- struct mail_session *mail_session_iter;
- struct mail_user *mail_user_iter;
- struct mail_domain *mail_domain_iter;
- struct mail_ip *mail_ip_iter;
-};
-
-struct client *client_create(int fd);
-void client_destroy(struct client **client);
-
-bool client_is_busy(struct client *client);
-void client_enable_io(struct client *client);
-
-void clients_destroy_all(void);
-
-#endif
+++ /dev/null
-/* Copyright (c) 2011-2018 Dovecot authors, see the included COPYING file */
-
-#include "lib.h"
-#include "llist.h"
-#include "strescape.h"
-#include "istream.h"
-#include "ostream.h"
-#include "master-service.h"
-#include "mail-session.h"
-#include "mail-user.h"
-#include "mail-command.h"
-#include "fifo-input-connection.h"
-
-#include <unistd.h>
-
-#define MAX_INBUF_SIZE (PIPE_BUF*2)
-
-struct fifo_input_connection {
- struct fifo_input_connection *prev, *next;
-
- int fd;
- struct istream *input;
- struct io *io;
-};
-
-static struct fifo_input_connection *fifo_conns = NULL;
-
-static int
-fifo_input_connection_request(const char *const *args, const char **error_r)
-{
- const char *cmd = args[0];
-
- if (cmd == NULL) {
- *error_r = "Missing command";
- return -1;
- }
- args++;
-
- if (strcmp(cmd, "CONNECT") == 0)
- return mail_session_connect_parse(args, error_r);
- if (strcmp(cmd, "DISCONNECT") == 0)
- return mail_session_disconnect_parse(args, error_r);
- if (strcmp(cmd, "UPDATE-SESSION") == 0)
- return mail_session_update_parse(args, error_r);
- if (strcmp(cmd, "ADD-USER") == 0)
- return mail_user_add_parse(args, error_r);
- if (strcmp(cmd, "UPDATE-CMD") == 0)
- return mail_command_update_parse(args, error_r);
-
- *error_r = "Unknown command";
- return -1;
-}
-
-static void fifo_input_connection_input(struct fifo_input_connection *conn)
-{
- const char *line, *const *args, *error;
-
- switch (i_stream_read(conn->input)) {
- case -2:
- i_error("BUG: Mail server sent too much data");
- fifo_input_connection_destroy(&conn);
- return;
- case -1:
- fifo_input_connection_destroy(&conn);
- return;
- }
-
- while ((line = i_stream_next_line(conn->input)) != NULL) T_BEGIN {
- args = t_strsplit_tabescaped(line);
- if (fifo_input_connection_request(args, &error) < 0)
- i_error("FIFO input error: %s", error);
- } T_END;
-}
-
-struct fifo_input_connection *fifo_input_connection_create(int fd)
-{
- struct fifo_input_connection *conn;
-
- conn = i_new(struct fifo_input_connection, 1);
- conn->fd = fd;
- conn->input = i_stream_create_fd(fd, MAX_INBUF_SIZE);
- conn->io = io_add(fd, IO_READ, fifo_input_connection_input, conn);
- DLLIST_PREPEND(&fifo_conns, conn);
- return conn;
-}
-
-void fifo_input_connection_destroy(struct fifo_input_connection **_conn)
-{
- struct fifo_input_connection *conn = *_conn;
-
- *_conn = NULL;
-
- DLLIST_REMOVE(&fifo_conns, conn);
- io_remove(&conn->io);
- i_stream_destroy(&conn->input);
- if (close(conn->fd) < 0)
- i_error("close(conn) failed: %m");
- i_free(conn);
-}
-
-void fifo_input_connections_destroy_all(void)
-{
- while (fifo_conns != NULL) {
- struct fifo_input_connection *conn = fifo_conns;
-
- fifo_input_connection_destroy(&conn);
- }
-}
+++ /dev/null
-#ifndef FIFO_INPUT_CONNECTION_H
-#define FIFO_INPUT_CONNECTION_H
-
-struct fifo_input_connection *fifo_input_connection_create(int fd);
-void fifo_input_connection_destroy(struct fifo_input_connection **conn);
-
-void fifo_input_connections_destroy_all(void);
-
-#endif
+++ /dev/null
-/* Copyright (c) 2011-2018 Dovecot authors, see the included COPYING file */
-
-#include "lib.h"
-#include "mail-command.h"
-#include "mail-session.h"
-#include "mail-user.h"
-#include "mail-domain.h"
-#include "mail-ip.h"
-#include "stats-settings.h"
-#include "global-memory.h"
-
-size_t global_used_memory = 0;
-
-static bool global_memory_free_something(void)
-{
- size_t orig_used_memory = global_used_memory;
-
- mail_commands_free_memory();
- if (global_used_memory > stats_settings->memory_limit)
- mail_sessions_free_memory();
- if (global_used_memory > stats_settings->memory_limit)
- mail_users_free_memory();
- if (global_used_memory > stats_settings->memory_limit)
- mail_ips_free_memory();
- if (global_used_memory > stats_settings->memory_limit)
- mail_domains_free_memory();
-
- return global_used_memory < orig_used_memory;
-}
-
-void global_memory_alloc(size_t size)
-{
- i_assert(size < SIZE_MAX - global_used_memory);
- global_used_memory += size;
-
- while (global_used_memory > stats_settings->memory_limit) {
- if (!global_memory_free_something())
- break;
- }
-}
-
-void global_memory_free(size_t size)
-{
- i_assert(size <= global_used_memory);
- global_used_memory -= size;
-}
+++ /dev/null
-#ifndef GLOBAL_MEMORY_H
-#define GLOBAL_MEMORY_H
-
-extern size_t global_used_memory;
-
-void global_memory_alloc(size_t size);
-void global_memory_free(size_t size);
-
-#endif
+++ /dev/null
-/* Copyright (c) 2011-2018 Dovecot authors, see the included COPYING file */
-
-#include "lib.h"
-#include "buffer.h"
-#include "base64.h"
-#include "ioloop.h"
-#include "llist.h"
-#include "global-memory.h"
-#include "stats-settings.h"
-#include "mail-stats.h"
-#include "mail-session.h"
-#include "mail-command.h"
-
-#define MAIL_COMMAND_TIMEOUT_SECS (60*15)
-
-/* commands are sorted by their last_update timestamp, oldest first */
-struct mail_command *stable_mail_commands_head;
-struct mail_command *stable_mail_commands_tail;
-
-static size_t mail_command_memsize(const struct mail_command *cmd)
-{
- return sizeof(*cmd) + strlen(cmd->name) + 1 + strlen(cmd->args) + 1;
-}
-
-static struct mail_command *
-mail_command_find(struct mail_session *session, unsigned int id)
-{
- struct mail_command *cmd;
-
- i_assert(id != 0);
-
- if (id > session->highest_cmd_id) {
- /* fast path for new commands */
- return NULL;
- }
- for (cmd = session->commands; cmd != NULL; cmd = cmd->session_next) {
- if (cmd->id == id)
- return cmd;
- }
- /* expired */
- return NULL;
-}
-
-static struct mail_command *
-mail_command_add(struct mail_session *session, const char *name,
- const char *args)
-{
- struct mail_command *cmd;
-
- cmd = i_malloc(MALLOC_ADD(sizeof(struct mail_command), stats_alloc_size()));
- cmd->stats = (void *)(cmd + 1);
- cmd->refcount = 1; /* unrefed at "done" */
- cmd->session = session;
- cmd->name = i_strdup(name);
- cmd->args = i_strdup(args);
- cmd->last_update = ioloop_timeval;
-
- DLLIST2_APPEND_FULL(&stable_mail_commands_head,
- &stable_mail_commands_tail, cmd,
- stable_prev, stable_next);
- DLLIST_PREPEND_FULL(&session->commands, cmd,
- session_prev, session_next);
- mail_session_ref(cmd->session);
- global_memory_alloc(mail_command_memsize(cmd));
- return cmd;
-}
-
-static void mail_command_free(struct mail_command *cmd)
-{
- i_assert(cmd->refcount == 0);
-
- global_memory_free(mail_command_memsize(cmd));
-
- DLLIST2_REMOVE_FULL(&stable_mail_commands_head,
- &stable_mail_commands_tail, cmd,
- stable_prev, stable_next);
- DLLIST_REMOVE_FULL(&cmd->session->commands, cmd,
- session_prev, session_next);
- mail_session_unref(&cmd->session);
- i_free(cmd->name);
- i_free(cmd->args);
- i_free(cmd);
-}
-
-void mail_command_ref(struct mail_command *cmd)
-{
- cmd->refcount++;
-}
-
-void mail_command_unref(struct mail_command **_cmd)
-{
- struct mail_command *cmd = *_cmd;
-
- i_assert(cmd->refcount > 0);
- cmd->refcount--;
-
- *_cmd = NULL;
-}
-
-int mail_command_update_parse(const char *const *args, const char **error_r)
-{
- struct mail_session *session;
- struct mail_command *cmd;
- struct stats *new_stats, *diff_stats;
- buffer_t *buf;
- const char *error;
- unsigned int i, cmd_id;
- bool done = FALSE, continued = FALSE;
-
- /* <session guid> <cmd id> [d] <name> <args> <stats>
- <session guid> <cmd id> c[d] <stats> */
- if (str_array_length(args) < 3) {
- *error_r = "UPDATE-CMD: Too few parameters";
- return -1;
- }
- if (mail_session_get(args[0], &session, error_r) < 0)
- return -1;
-
- if (str_to_uint(args[1], &cmd_id) < 0 || cmd_id == 0) {
- *error_r = "UPDATE-CMD: Invalid command id";
- return -1;
- }
- for (i = 0; args[2][i] != '\0'; i++) {
- switch (args[2][i]) {
- case 'd':
- done = TRUE;
- break;
- case 'c':
- continued = TRUE;
- break;
- default:
- *error_r = "UPDATE-CMD: Invalid flags parameter";
- return -1;
- }
- }
-
- cmd = mail_command_find(session, cmd_id);
- if (!continued) {
- /* new command */
- if (cmd != NULL) {
- *error_r = "UPDATE-CMD: Duplicate new command id";
- return -1;
- }
- if (str_array_length(args) < 5) {
- *error_r = "UPDATE-CMD: Too few parameters";
- return -1;
- }
- cmd = mail_command_add(session, args[3], args[4]);
- cmd->id = cmd_id;
-
- session->highest_cmd_id =
- I_MAX(session->highest_cmd_id, cmd_id);
- session->num_cmds++;
- session->user->num_cmds++;
- session->user->domain->num_cmds++;
- if (session->ip != NULL)
- session->ip->num_cmds++;
- mail_global_stats.num_cmds++;
- args += 5;
- } else {
- if (cmd == NULL) {
- /* already expired command, ignore */
- i_warning("UPDATE-CMD: Already expired");
- return 0;
- }
- args += 3;
- cmd->last_update = ioloop_timeval;
- }
- buf = t_buffer_create(256);
- if (args[0] == NULL ||
- base64_decode(args[0], strlen(args[0]), NULL, buf) < 0) {
- *error_r = t_strdup_printf("UPDATE-CMD: Invalid base64 input");
- return -1;
- }
-
- new_stats = stats_alloc(pool_datastack_create());
- diff_stats = stats_alloc(pool_datastack_create());
-
- if (!stats_import(buf->data, buf->used, cmd->stats, new_stats, &error)) {
- *error_r = t_strdup_printf("UPDATE-CMD: %s", error);
- return -1;
- }
-
- if (!stats_diff(cmd->stats, new_stats, diff_stats, &error)) {
- *error_r = t_strdup_printf("UPDATE-CMD: stats shrank: %s", error);
- return -1;
- }
- stats_add(cmd->stats, diff_stats);
-
- if (done) {
- cmd->id = 0;
- mail_command_unref(&cmd);
- }
- mail_session_refresh(session, NULL);
- return 0;
-}
-
-static bool mail_command_is_timed_out(struct mail_command *cmd)
-{
- /* some commands like IDLE can run forever */
- return ioloop_time - cmd->last_update.tv_sec >
- MAIL_COMMAND_TIMEOUT_SECS;
-}
-
-void mail_commands_free_memory(void)
-{
- unsigned int diff;
-
- while (stable_mail_commands_head != NULL) {
- struct mail_command *cmd = stable_mail_commands_head;
-
- if (cmd->refcount == 0)
- i_assert(cmd->id == 0);
- else if (cmd->refcount == 1 &&
- (cmd->session->disconnected ||
- mail_command_is_timed_out(cmd))) {
- /* session was probably lost */
- mail_command_unref(&cmd);
- } else {
- break;
- }
- mail_command_free(stable_mail_commands_head);
-
- if (global_used_memory < stats_settings->memory_limit ||
- stable_mail_commands_head == NULL)
- break;
-
- diff = ioloop_time - stable_mail_commands_head->last_update.tv_sec;
- if (diff < stats_settings->command_min_time)
- break;
- }
-}
-
-void mail_commands_init(void)
-{
-}
-
-void mail_commands_deinit(void)
-{
- while (stable_mail_commands_head != NULL) {
- struct mail_command *cmd = stable_mail_commands_head;
-
- if (cmd->id != 0)
- mail_command_unref(&cmd);
- mail_command_free(stable_mail_commands_head);
- }
-}
+++ /dev/null
-#ifndef MAIL_COMMAND_H
-#define MAIL_COMMAND_H
-
-struct mail_command;
-
-extern struct mail_command *stable_mail_commands_head;
-extern struct mail_command *stable_mail_commands_tail;
-
-int mail_command_update_parse(const char *const *args, const char **error_r);
-
-void mail_command_ref(struct mail_command *cmd);
-void mail_command_unref(struct mail_command **cmd);
-
-void mail_commands_free_memory(void);
-void mail_commands_init(void);
-void mail_commands_deinit(void);
-
-#endif
+++ /dev/null
-/* Copyright (c) 2011-2018 Dovecot authors, see the included COPYING file */
-
-#include "lib.h"
-#include "ioloop.h"
-#include "hash.h"
-#include "llist.h"
-#include "global-memory.h"
-#include "stats-settings.h"
-#include "mail-stats.h"
-#include "mail-domain.h"
-
-static HASH_TABLE(char *, struct mail_domain *) mail_domains_hash;
-/* domains are sorted by their last_update timestamp, oldest first */
-static struct mail_domain *mail_domains_head, *mail_domains_tail;
-struct mail_domain *stable_mail_domains;
-
-static size_t mail_domain_memsize(const struct mail_domain *domain)
-{
- return sizeof(*domain) + strlen(domain->name) + 1;
-}
-
-struct mail_domain *mail_domain_login_create(const char *name)
-{
- struct mail_domain *domain;
-
- domain = hash_table_lookup(mail_domains_hash, name);
- if (domain != NULL) {
- return domain;
- }
-
- domain = i_malloc(MALLOC_ADD(sizeof(struct mail_domain), stats_alloc_size()));
- domain->stats = (void *)(domain + 1);
- domain->name = i_strdup(name);
- domain->reset_timestamp = ioloop_time;
-
- hash_table_insert(mail_domains_hash, domain->name, domain);
- DLLIST_PREPEND_FULL(&stable_mail_domains, domain,
- stable_prev, stable_next);
- global_memory_alloc(mail_domain_memsize(domain));
- return domain;
-}
-
-void mail_domain_login(struct mail_domain *domain)
-{
- domain->num_logins++;
- domain->num_connected_sessions++;
- mail_domain_refresh(domain, NULL);
-}
-
-void mail_domain_disconnected(struct mail_domain *domain)
-{
- i_assert(domain->num_connected_sessions > 0);
- domain->num_connected_sessions--;
- mail_global_disconnected();
-}
-
-struct mail_domain *mail_domain_lookup(const char *name)
-{
- return hash_table_lookup(mail_domains_hash, name);
-}
-
-void mail_domain_ref(struct mail_domain *domain)
-{
- domain->refcount++;
-}
-
-void mail_domain_unref(struct mail_domain **_domain)
-{
- struct mail_domain *domain = *_domain;
-
- i_assert(domain->refcount > 0);
- domain->refcount--;
-
- *_domain = NULL;
-}
-
-static void mail_domain_free(struct mail_domain *domain)
-{
- i_assert(domain->refcount == 0);
- i_assert(domain->users == NULL);
-
- global_memory_free(mail_domain_memsize(domain));
- hash_table_remove(mail_domains_hash, domain->name);
- DLLIST_REMOVE_FULL(&stable_mail_domains, domain,
- stable_prev, stable_next);
- DLLIST2_REMOVE_FULL(&mail_domains_head, &mail_domains_tail, domain,
- sorted_prev, sorted_next);
-
- i_free(domain->name);
- i_free(domain);
-}
-
-void mail_domain_refresh(struct mail_domain *domain,
- const struct stats *diff_stats)
-{
- if (diff_stats != NULL)
- stats_add(domain->stats, diff_stats);
- domain->last_update = ioloop_timeval;
- DLLIST2_REMOVE_FULL(&mail_domains_head, &mail_domains_tail, domain,
- sorted_prev, sorted_next);
- DLLIST2_APPEND_FULL(&mail_domains_head, &mail_domains_tail, domain,
- sorted_prev, sorted_next);
- mail_global_refresh(diff_stats);
-}
-
-void mail_domains_free_memory(void)
-{
- unsigned int diff;
-
- while (mail_domains_head != NULL && mail_domains_head->refcount == 0) {
- mail_domain_free(mail_domains_head);
-
- if (global_used_memory < stats_settings->memory_limit ||
- mail_domains_head == NULL)
- break;
-
- diff = ioloop_time - mail_domains_head->last_update.tv_sec;
- if (diff < stats_settings->domain_min_time)
- break;
- }
-}
-
-void mail_domains_init(void)
-{
- hash_table_create(&mail_domains_hash, default_pool, 0, str_hash, strcmp);
-}
-
-void mail_domains_deinit(void)
-{
- while (mail_domains_head != NULL)
- mail_domain_free(mail_domains_head);
- hash_table_destroy(&mail_domains_hash);
-}
+++ /dev/null
-#ifndef MAIL_DOMAIN_H
-#define MAIL_DOMAIN_H
-
-struct stats;
-
-extern struct mail_domain *stable_mail_domains;
-
-struct mail_domain *mail_domain_login_create(const char *name);
-void mail_domain_login(struct mail_domain *domain);
-void mail_domain_disconnected(struct mail_domain *domain);
-struct mail_domain *mail_domain_lookup(const char *name);
-void mail_domain_refresh(struct mail_domain *domain,
- const struct stats *diff_stats) ATTR_NULL(2);
-
-void mail_domain_ref(struct mail_domain *domain);
-void mail_domain_unref(struct mail_domain **domain);
-
-void mail_domains_free_memory(void);
-void mail_domains_init(void);
-void mail_domains_deinit(void);
-
-#endif
+++ /dev/null
-/* Copyright (c) 2011-2018 Dovecot authors, see the included COPYING file */
-
-#include "lib.h"
-#include "ioloop.h"
-#include "hash.h"
-#include "llist.h"
-#include "global-memory.h"
-#include "stats-settings.h"
-#include "mail-stats.h"
-#include "mail-ip.h"
-
-static HASH_TABLE(struct ip_addr *, struct mail_ip *) mail_ips_hash;
-/* ips are sorted by their last_update timestamp, oldest first */
-static struct mail_ip *mail_ips_head, *mail_ips_tail;
-struct mail_ip *stable_mail_ips;
-
-static size_t mail_ip_memsize(const struct mail_ip *ip)
-{
- return sizeof(*ip);
-}
-
-struct mail_ip *mail_ip_login(const struct ip_addr *ip_addr)
-{
- struct mail_ip *ip;
-
- ip = hash_table_lookup(mail_ips_hash, ip_addr);
- if (ip != NULL) {
- ip->num_logins++;
- ip->num_connected_sessions++;
- mail_ip_refresh(ip, NULL);
- return ip;
- }
-
- ip = i_malloc(MALLOC_ADD(sizeof(struct mail_ip), stats_alloc_size()));
- ip->stats = (void *)(ip + 1);
- ip->ip = *ip_addr;
- ip->reset_timestamp = ioloop_time;
-
- hash_table_insert(mail_ips_hash, &ip->ip, ip);
- DLLIST_PREPEND_FULL(&stable_mail_ips, ip, stable_prev, stable_next);
- DLLIST2_APPEND_FULL(&mail_ips_head, &mail_ips_tail, ip,
- sorted_prev, sorted_next);
- ip->num_logins++;
- ip->num_connected_sessions++;
- ip->last_update = ioloop_timeval;
- global_memory_alloc(mail_ip_memsize(ip));
- return ip;
-}
-
-void mail_ip_disconnected(struct mail_ip *ip)
-{
- i_assert(ip->num_connected_sessions > 0);
- ip->num_connected_sessions--;
-}
-
-struct mail_ip *mail_ip_lookup(const struct ip_addr *ip_addr)
-{
- return hash_table_lookup(mail_ips_hash, ip_addr);
-}
-
-void mail_ip_ref(struct mail_ip *ip)
-{
- ip->refcount++;
-}
-
-void mail_ip_unref(struct mail_ip **_ip)
-{
- struct mail_ip *ip = *_ip;
-
- i_assert(ip->refcount > 0);
- ip->refcount--;
-
- *_ip = NULL;
-}
-
-static void mail_ip_free(struct mail_ip *ip)
-{
- i_assert(ip->refcount == 0);
- i_assert(ip->sessions == NULL);
-
- global_memory_free(mail_ip_memsize(ip));
- hash_table_remove(mail_ips_hash, &ip->ip);
- DLLIST_REMOVE_FULL(&stable_mail_ips, ip, stable_prev, stable_next);
- DLLIST2_REMOVE_FULL(&mail_ips_head, &mail_ips_tail, ip,
- sorted_prev, sorted_next);
-
- i_free(ip);
-}
-
-void mail_ip_refresh(struct mail_ip *ip, const struct stats *diff_stats)
-{
- if (diff_stats != NULL)
- stats_add(ip->stats, diff_stats);
- ip->last_update = ioloop_timeval;
- DLLIST2_REMOVE_FULL(&mail_ips_head, &mail_ips_tail, ip,
- sorted_prev, sorted_next);
- DLLIST2_APPEND_FULL(&mail_ips_head, &mail_ips_tail, ip,
- sorted_prev, sorted_next);
-}
-
-void mail_ips_free_memory(void)
-{
- unsigned int diff;
-
- while (mail_ips_head != NULL && mail_ips_head->refcount == 0) {
- mail_ip_free(mail_ips_head);
-
- if (global_used_memory < stats_settings->memory_limit ||
- mail_ips_head == NULL)
- break;
-
- diff = ioloop_time - mail_ips_head->last_update.tv_sec;
- if (diff < stats_settings->ip_min_time)
- break;
- }
-}
-
-void mail_ips_init(void)
-{
- hash_table_create(&mail_ips_hash, default_pool, 0,
- net_ip_hash, net_ip_cmp);
-}
-
-void mail_ips_deinit(void)
-{
- while (mail_ips_head != NULL)
- mail_ip_free(mail_ips_head);
- hash_table_destroy(&mail_ips_hash);
-}
+++ /dev/null
-#ifndef MAIL_IP_H
-#define MAIL_IP_H
-
-extern struct mail_ip *stable_mail_ips;
-
-struct mail_ip *mail_ip_login(const struct ip_addr *ip_addr);
-void mail_ip_disconnected(struct mail_ip *ip);
-struct mail_ip *mail_ip_lookup(const struct ip_addr *ip_addr);
-void mail_ip_refresh(struct mail_ip *ip, const struct stats *diff_stats)
- ATTR_NULL(2);
-
-void mail_ip_ref(struct mail_ip *ip);
-void mail_ip_unref(struct mail_ip **ip);
-
-void mail_ips_free_memory(void);
-void mail_ips_init(void);
-void mail_ips_deinit(void);
-
-#endif
+++ /dev/null
-/* Copyright (c) 2011-2018 Dovecot authors, see the included COPYING file */
-
-#include "lib.h"
-#include "buffer.h"
-#include "base64.h"
-#include "ioloop.h"
-#include "hash.h"
-#include "llist.h"
-#include "str-table.h"
-#include "global-memory.h"
-#include "stats-settings.h"
-#include "mail-stats.h"
-#include "mail-user.h"
-#include "mail-ip.h"
-#include "mail-session.h"
-#include "mail-domain.h"
-
-/* If session doesn't receive any updates for this long, assume that the
- process associated with it has crashed, and forcibly disconnect the
- session. Must be larger than SESSION_STATS_FORCE_REFRESH_SECS in
- stats plugin */
-#define MAIL_SESSION_IDLE_TIMEOUT_MSECS (1000*60*15)
-/* If stats process crashes/restarts, existing processes keep sending status
- updates to it, but this process doesn't know their session IDs. If these
- missing IDs are found within this many seconds of starting the stats process,
- don't log a warning about them. (On a larger installation this avoids
- flooding the error log with hundreds of warnings.) */
-#define SESSION_ID_WARN_HIDE_SECS (60*5)
-
-static HASH_TABLE(char *, struct mail_session *) mail_sessions_hash;
-/* sessions are sorted by their last_update timestamp, oldest first */
-static struct mail_session *mail_sessions_head, *mail_sessions_tail;
-static time_t session_id_warn_hide_until;
-static bool session_id_hide_warned = FALSE;
-static struct str_table *services;
-
-struct mail_session *stable_mail_sessions;
-
-static size_t mail_session_memsize(const struct mail_session *session)
-{
- return sizeof(*session) + strlen(session->id) + 1;
-}
-
-static void mail_session_disconnect(struct mail_session *session)
-{
- i_assert(!session->disconnected);
-
- mail_user_disconnected(session->user);
- if (session->ip != NULL)
- mail_ip_disconnected(session->ip);
-
- hash_table_remove(mail_sessions_hash, session->id);
- session->disconnected = TRUE;
- timeout_remove(&session->to_idle);
- mail_session_unref(&session);
-}
-
-static void mail_session_idle_timeout(struct mail_session *session)
-{
- /* user="" service="" pid=0 is used for incoming sessions that were
- received after we detected a stats process crash/restart. there's
- no point in logging anything about them, since they contain no
- useful information. */
- if (session->user->name[0] == '\0' && session->service[0] != '\0' &&
- session->pid == 0) {
- i_warning("Session %s (user %s, service %s) "
- "appears to have crashed, disconnecting it",
- session->id, session->user->name, session->service);
- }
- mail_session_disconnect(session);
-}
-
-int mail_session_connect_parse(const char *const *args, const char **error_r)
-{
- struct mail_session *session;
- const char *session_id;
- pid_t pid;
- struct ip_addr ip;
- unsigned int i;
-
- /* <session id> <username> <service> <pid> [key=value ..] */
- if (str_array_length(args) < 4) {
- *error_r = "CONNECT: Too few parameters";
- return -1;
- }
- session_id = args[0];
- if (str_to_pid(args[3], &pid) < 0) {
- *error_r = t_strdup_printf("CONNECT: Invalid pid %s for session ID %s",
- args[3], session_id);
- return -1;
- }
-
- session = hash_table_lookup(mail_sessions_hash, session_id);
- if (session != NULL) {
- *error_r = t_strdup_printf(
- "CONNECT: Duplicate session ID %s for user %s service %s (old PID %ld, new PID %ld)",
- session_id, args[1], args[2], (long)session->pid, (long)pid);
- return -1;
- }
- session = i_malloc(MALLOC_ADD(sizeof(struct mail_session), stats_alloc_size()));
- session->stats = (void *)(session + 1);
- session->refcount = 1; /* unrefed at disconnect */
- session->id = i_strdup(session_id);
- session->service = str_table_ref(services, args[2]);
- session->pid = pid;
- session->last_update = ioloop_timeval;
- session->to_idle = timeout_add(MAIL_SESSION_IDLE_TIMEOUT_MSECS,
- mail_session_idle_timeout, session);
-
- session->user = mail_user_login(args[1]);
- session->user->num_logins++;
- mail_domain_login(session->user->domain);
-
- for (i = 3; args[i] != NULL; i++) {
- if (str_begins(args[i], "rip=") &&
- net_addr2ip(args[i] + 4, &ip) == 0)
- session->ip = mail_ip_login(&ip);
- }
-
- hash_table_insert(mail_sessions_hash, session->id, session);
- DLLIST_PREPEND_FULL(&stable_mail_sessions, session,
- stable_prev, stable_next);
- DLLIST2_APPEND_FULL(&mail_sessions_head, &mail_sessions_tail, session,
- sorted_prev, sorted_next);
- DLLIST_PREPEND_FULL(&session->user->sessions, session,
- user_prev, user_next);
- mail_user_ref(session->user);
- if (session->ip != NULL) {
- DLLIST_PREPEND_FULL(&session->ip->sessions, session,
- ip_prev, ip_next);
- mail_ip_ref(session->ip);
- }
- global_memory_alloc(mail_session_memsize(session));
-
- mail_global_login();
- return 0;
-}
-
-void mail_session_ref(struct mail_session *session)
-{
- session->refcount++;
-}
-
-void mail_session_unref(struct mail_session **_session)
-{
- struct mail_session *session = *_session;
-
- i_assert(session->refcount > 0);
- session->refcount--;
-
- *_session = NULL;
-}
-
-static void mail_session_free(struct mail_session *session)
-{
- i_assert(session->refcount == 0);
-
- global_memory_free(mail_session_memsize(session));
-
- timeout_remove(&session->to_idle);
- if (!session->disconnected)
- hash_table_remove(mail_sessions_hash, session->id);
- DLLIST_REMOVE_FULL(&stable_mail_sessions, session,
- stable_prev, stable_next);
- DLLIST2_REMOVE_FULL(&mail_sessions_head, &mail_sessions_tail, session,
- sorted_prev, sorted_next);
- DLLIST_REMOVE_FULL(&session->user->sessions, session,
- user_prev, user_next);
- mail_user_unref(&session->user);
- if (session->ip != NULL) {
- DLLIST_REMOVE_FULL(&session->ip->sessions, session,
- ip_prev, ip_next);
- mail_ip_unref(&session->ip);
- }
-
- str_table_unref(services, &session->service);
- i_free(session->id);
- i_free(session);
-}
-
-static void mail_session_id_lost(const char *session_id)
-{
- if (ioloop_time < session_id_warn_hide_until) {
- if (session_id_hide_warned)
- return;
- session_id_hide_warned = TRUE;
- i_warning("stats process appears to have crashed/restarted, "
- "hiding missing session ID warnings for %d seconds",
- (int)(session_id_warn_hide_until - ioloop_time));
- return;
- }
- i_warning("Couldn't find session ID: %s", session_id);
-}
-
-int mail_session_lookup(const char *id, struct mail_session **session_r,
- const char **error_r)
-{
- if (id == NULL) {
- *error_r = "Too few parameters";
- return -1;
- }
- *session_r = hash_table_lookup(mail_sessions_hash, id);
- if (*session_r == NULL) {
- mail_session_id_lost(id);
- return 0;
- }
- return 1;
-}
-
-int mail_session_get(const char *id, struct mail_session **session_r,
- const char **error_r)
-{
- const char *new_args[5];
- int ret;
-
- if ((ret = mail_session_lookup(id, session_r, error_r)) != 0)
- return ret;
-
- /* Create a new dummy session to avoid repeated warnings */
- new_args[0] = id;
- new_args[1] = ""; /* username */
- new_args[2] = ""; /* service */
- new_args[3] = "0"; /* pid */
- new_args[4] = NULL;
- if (mail_session_connect_parse(new_args, error_r) < 0)
- i_unreached();
- if (mail_session_lookup(id, session_r, error_r) != 1)
- i_unreached();
- return 0;
-}
-
-int mail_session_disconnect_parse(const char *const *args, const char **error_r)
-{
- struct mail_session *session;
- int ret;
-
- /* <session id> */
- if ((ret = mail_session_lookup(args[0], &session, error_r)) <= 0)
- return ret;
-
- if (!session->disconnected)
- mail_session_disconnect(session);
- return 0;
-}
-
-void mail_session_refresh(struct mail_session *session,
- const struct stats *diff_stats)
-{
- timeout_reset(session->to_idle);
-
- if (diff_stats != NULL)
- stats_add(session->stats, diff_stats);
- session->last_update = ioloop_timeval;
- DLLIST2_REMOVE_FULL(&mail_sessions_head, &mail_sessions_tail, session,
- sorted_prev, sorted_next);
- DLLIST2_APPEND_FULL(&mail_sessions_head, &mail_sessions_tail, session,
- sorted_prev, sorted_next);
-
- mail_user_refresh(session->user, diff_stats);
- if (session->ip != NULL)
- mail_ip_refresh(session->ip, diff_stats);
-}
-
-int mail_session_update_parse(const char *const *args, const char **error_r)
-{
- struct mail_session *session;
- struct stats *new_stats, *diff_stats;
- buffer_t *buf;
- const char *error;
-
- /* <session id> <stats> */
- if (mail_session_get(args[0], &session, error_r) < 0)
- return -1;
-
- buf = t_buffer_create(256);
- if (args[1] == NULL ||
- base64_decode(args[1], strlen(args[1]), NULL, buf) < 0) {
- *error_r = t_strdup_printf("UPDATE-SESSION %s %s %s: Invalid base64 input",
- session->user->name,
- session->service, session->id);
- return -1;
- }
-
- new_stats = stats_alloc(pool_datastack_create());
- diff_stats = stats_alloc(pool_datastack_create());
-
- if (!stats_import(buf->data, buf->used, session->stats, new_stats, &error)) {
- *error_r = t_strdup_printf("UPDATE-SESSION %s %s %s: %s",
- session->user->name,
- session->service, session->id, error);
- return -1;
- }
-
- if (!stats_diff(session->stats, new_stats, diff_stats, &error)) {
- *error_r = t_strdup_printf("UPDATE-SESSION %s %s %s: stats shrank: %s",
- session->user->name,
- session->service, session->id, error);
- return -1;
- }
- mail_session_refresh(session, diff_stats);
- return 0;
-}
-
-void mail_sessions_free_memory(void)
-{
- unsigned int diff;
-
- while (mail_sessions_head != NULL &&
- mail_sessions_head->refcount == 0) {
- i_assert(mail_sessions_head->disconnected);
- mail_session_free(mail_sessions_head);
-
- if (global_used_memory < stats_settings->memory_limit ||
- mail_sessions_head == NULL)
- break;
-
- diff = ioloop_time - mail_sessions_head->last_update.tv_sec;
- if (diff < stats_settings->session_min_time)
- break;
- }
-}
-
-void mail_sessions_init(void)
-{
- session_id_warn_hide_until =
- ioloop_time + SESSION_ID_WARN_HIDE_SECS;
- hash_table_create(&mail_sessions_hash, default_pool, 0,
- str_hash, strcmp);
- services = str_table_init();
-}
-
-void mail_sessions_deinit(void)
-{
- while (mail_sessions_head != NULL) {
- struct mail_session *session = mail_sessions_head;
-
- if (!session->disconnected)
- mail_session_unref(&session);
- mail_session_free(mail_sessions_head);
- }
- hash_table_destroy(&mail_sessions_hash);
- str_table_deinit(&services);
-}
+++ /dev/null
-#ifndef MAIL_SESSION_H
-#define MAIL_SESSION_H
-
-struct stats;
-struct mail_session;
-
-extern struct mail_session *stable_mail_sessions;
-
-int mail_session_connect_parse(const char *const *args, const char **error_r);
-int mail_session_disconnect_parse(const char *const *args, const char **error_r);
-int mail_session_update_parse(const char *const *args, const char **error_r);
-int mail_session_cmd_update_parse(const char *const *args, const char **error_r);
-
-void mail_session_ref(struct mail_session *session);
-void mail_session_unref(struct mail_session **session);
-
-int mail_session_lookup(const char *guid, struct mail_session **session_r,
- const char **error_r);
-int mail_session_get(const char *guid, struct mail_session **session_r,
- const char **error_r);
-void mail_session_refresh(struct mail_session *session,
- const struct stats *diff_stats) ATTR_NULL(2);
-
-void mail_sessions_free_memory(void);
-void mail_sessions_init(void);
-void mail_sessions_deinit(void);
-
-#endif
+++ /dev/null
-/* Copyright (c) 2011-2018 Dovecot authors, see the included COPYING file */
-
-#include "lib.h"
-#include "ioloop.h"
-#include "mail-stats.h"
-#include "stats-carbon.h"
-#include "stats-settings.h"
-#include "str.h"
-
-struct mail_global mail_global_stats;
-
-static void
-mail_global_stats_sent(void *ctx)
-{
- struct mail_global *stats = ctx;
- stats_carbon_destroy(&stats->stats_send_ctx);
-}
-
-static void
-mail_global_stats_send(void *u0 ATTR_UNUSED)
-{
- time_t ts = ioloop_time;
- if (*stats_settings->carbon_name != '\0' &&
- *stats_settings->carbon_server != '\0') {
- string_t *str = t_str_new(256);
- const char *prefix = t_strdup_printf("dovecot.%s.global",
- stats_settings->carbon_name);
- str_printfa(str, "%s.logins %u %"PRIdTIME_T"\r\n", prefix,
- mail_global_stats.num_logins, ts);
- str_printfa(str, "%s.cmds %u %"PRIdTIME_T"\r\n", prefix,
- mail_global_stats.num_cmds, ts);
- str_printfa(str, "%s.connected_sessions %u %"PRIdTIME_T"\r\n",
- prefix, mail_global_stats.num_connected_sessions,
- ts);
- str_printfa(str, "%s.last_reset %"PRIdTIME_T" %"PRIdTIME_T"\r\n",
- prefix, mail_global_stats.reset_timestamp, ts);
- /* then export rest of the stats */
- for(size_t i = 0; i < stats_field_count(); i++) {
- str_printfa(str, "%s.%s ", prefix,
- stats_field_name(i));
- stats_field_value(str, mail_global_stats.stats, i);
- str_printfa(str, " %"PRIdTIME_T"\r\n", ts);
- }
-
- /* and send them along */
- (void)stats_carbon_send(stats_settings->carbon_server, str_c(str),
- mail_global_stats_sent, &mail_global_stats,
- &mail_global_stats.stats_send_ctx);
- }
-}
-
-void mail_global_init(void)
-{
- mail_global_stats.reset_timestamp = ioloop_time;
- mail_global_stats.stats = stats_alloc(default_pool);
- mail_global_stats.to_stats_send = timeout_add(stats_settings->carbon_interval*1000,
- mail_global_stats_send,
- NULL);
-}
-
-void mail_global_deinit(void)
-{
- if (mail_global_stats.stats_send_ctx != NULL)
- stats_carbon_destroy(&mail_global_stats.stats_send_ctx);
- timeout_remove(&mail_global_stats.to_stats_send);
- i_free(mail_global_stats.stats);
-}
-
-void mail_global_login(void)
-{
- mail_global_stats.num_logins++;
- mail_global_stats.num_connected_sessions++;
-}
-
-void mail_global_disconnected(void)
-{
- i_assert(mail_global_stats.num_connected_sessions > 0);
- mail_global_stats.num_connected_sessions--;
-}
-
-void mail_global_refresh(const struct stats *diff_stats)
-{
- if (diff_stats != NULL)
- stats_add(mail_global_stats.stats, diff_stats);
- mail_global_stats.last_update = ioloop_timeval;
-}
+++ /dev/null
-#ifndef MAIL_STATS_H
-#define MAIL_STATS_H
-
-#include <sys/time.h>
-
-#include "net.h"
-#include "guid.h"
-#include "stats.h"
-
-struct stats_send_ctx;
-
-struct mail_command {
- struct mail_command *stable_prev, *stable_next;
- struct mail_command *session_prev, *session_next;
-
- struct mail_session *session;
- char *name, *args;
- /* non-zero id means the command is still running */
- unsigned int id;
-
- struct timeval last_update;
- struct stats *stats;
-
- int refcount;
-};
-
-struct mail_session {
- struct mail_session *stable_prev, *stable_next;
- struct mail_session *sorted_prev, *sorted_next;
- struct mail_session *user_prev, *user_next;
- struct mail_session *ip_prev, *ip_next;
-
- /* if id="", the session no longer exists */
- char *id;
- struct mail_user *user;
- const char *service;
- pid_t pid;
- /* ip address may be NULL if there's none */
- struct mail_ip *ip;
- struct timeout *to_idle;
-
- struct stats *stats;
- struct timeval last_update;
- unsigned int num_cmds;
-
- bool disconnected;
- unsigned int highest_cmd_id;
- int refcount;
- struct mail_command *commands;
-};
-
-struct mail_user {
- struct mail_user *stable_prev, *stable_next;
- struct mail_user *sorted_prev, *sorted_next;
- struct mail_user *domain_prev, *domain_next;
- char *name;
- struct mail_domain *domain;
- time_t reset_timestamp;
-
- struct timeval last_update;
- struct stats *stats;
- unsigned int num_logins;
- unsigned int num_cmds;
-
- int refcount;
- struct mail_session *sessions;
-};
-
-struct mail_domain {
- struct mail_domain *stable_prev, *stable_next;
- struct mail_domain *sorted_prev, *sorted_next;
- char *name;
- time_t reset_timestamp;
-
- struct timeval last_update;
- struct stats *stats;
- unsigned int num_logins;
- unsigned int num_cmds;
- unsigned int num_connected_sessions;
-
- int refcount;
- struct mail_user *users;
-};
-
-struct mail_ip {
- struct mail_ip *stable_prev, *stable_next;
- struct mail_ip *sorted_prev, *sorted_next;
- struct ip_addr ip;
- time_t reset_timestamp;
-
- struct timeval last_update;
- struct stats *stats;
- unsigned int num_logins;
- unsigned int num_cmds;
- unsigned int num_connected_sessions;
-
- int refcount;
- struct mail_session *sessions;
-};
-
-struct mail_global {
- time_t reset_timestamp;
-
- struct timeval last_update;
- struct stats *stats;
- unsigned int num_logins;
- unsigned int num_cmds;
- unsigned int num_connected_sessions;
-
- struct timeout *to_stats_send;
- struct stats_send_ctx *stats_send_ctx;
-};
-
-extern struct mail_global mail_global_stats;
-
-void mail_global_init(void);
-void mail_global_deinit(void);
-
-void mail_global_login(void);
-void mail_global_disconnected(void);
-void mail_global_refresh(const struct stats *diff_stats);
-
-#endif
+++ /dev/null
-/* Copyright (c) 2011-2018 Dovecot authors, see the included COPYING file */
-
-#include "lib.h"
-#include "buffer.h"
-#include "ioloop.h"
-#include "hash.h"
-#include "llist.h"
-#include "base64.h"
-#include "global-memory.h"
-#include "stats-settings.h"
-#include "mail-stats.h"
-#include "mail-domain.h"
-#include "mail-user.h"
-
-static HASH_TABLE(char *, struct mail_user *) mail_users_hash;
-/* users are sorted by their last_update timestamp, oldest first */
-static struct mail_user *mail_users_head, *mail_users_tail;
-struct mail_user *stable_mail_users;
-
-static size_t mail_user_memsize(const struct mail_user *user)
-{
- return sizeof(*user) + strlen(user->name) + 1;
-}
-
-struct mail_user *mail_user_login(const char *username)
-{
- struct mail_user *user;
- const char *domain;
-
- user = hash_table_lookup(mail_users_hash, username);
- if (user != NULL) {
- mail_user_refresh(user, NULL);
- return user;
- }
-
- domain = i_strchr_to_next(username, '@');
- if (domain == NULL)
- domain = "";
-
- user = i_malloc(MALLOC_ADD(sizeof(struct mail_user), stats_alloc_size()));
- user->stats = (void *)(user + 1);
- user->name = i_strdup(username);
- user->reset_timestamp = ioloop_time;
- user->domain = mail_domain_login_create(domain);
-
- hash_table_insert(mail_users_hash, user->name, user);
- DLLIST_PREPEND_FULL(&stable_mail_users, user,
- stable_prev, stable_next);
- DLLIST2_APPEND_FULL(&mail_users_head, &mail_users_tail, user,
- sorted_prev, sorted_next);
- DLLIST_PREPEND_FULL(&user->domain->users, user,
- domain_prev, domain_next);
- mail_domain_ref(user->domain);
-
- user->last_update = ioloop_timeval;
- global_memory_alloc(mail_user_memsize(user));
- return user;
-}
-
-void mail_user_disconnected(struct mail_user *user)
-{
- mail_domain_disconnected(user->domain);
-}
-
-struct mail_user *mail_user_lookup(const char *username)
-{
- return hash_table_lookup(mail_users_hash, username);
-}
-
-void mail_user_ref(struct mail_user *user)
-{
- user->refcount++;
-}
-
-void mail_user_unref(struct mail_user **_user)
-{
- struct mail_user *user = *_user;
-
- i_assert(user->refcount > 0);
- user->refcount--;
-
- *_user = NULL;
-}
-
-static void mail_user_free(struct mail_user *user)
-{
- i_assert(user->refcount == 0);
- i_assert(user->sessions == NULL);
-
- global_memory_free(mail_user_memsize(user));
- hash_table_remove(mail_users_hash, user->name);
- DLLIST_REMOVE_FULL(&stable_mail_users, user,
- stable_prev, stable_next);
- DLLIST2_REMOVE_FULL(&mail_users_head, &mail_users_tail, user,
- sorted_prev, sorted_next);
- DLLIST_REMOVE_FULL(&user->domain->users, user,
- domain_prev, domain_next);
- mail_domain_unref(&user->domain);
-
- i_free(user->name);
- i_free(user);
-}
-
-void mail_user_refresh(struct mail_user *user,
- const struct stats *diff_stats)
-{
- if (diff_stats != NULL)
- stats_add(user->stats, diff_stats);
- user->last_update = ioloop_timeval;
- DLLIST2_REMOVE_FULL(&mail_users_head, &mail_users_tail, user,
- sorted_prev, sorted_next);
- DLLIST2_APPEND_FULL(&mail_users_head, &mail_users_tail, user,
- sorted_prev, sorted_next);
- mail_domain_refresh(user->domain, diff_stats);
-}
-
-int mail_user_add_parse(const char *const *args, const char **error_r)
-{
- struct mail_user *user;
- struct stats *empty_stats, *diff_stats;
- buffer_t *buf;
- const char *service, *error;
-
- /* <user> <service> <diff stats> */
- if (str_array_length(args) < 3) {
- *error_r = "ADD-USER: Too few parameters";
- return -1;
- }
-
- user = mail_user_login(args[0]);
- service = args[1];
-
- buf = t_buffer_create(256);
- if (base64_decode(args[2], strlen(args[2]), NULL, buf) < 0) {
- *error_r = t_strdup_printf("ADD-USER %s %s: Invalid base64 input",
- user->name, service);
- return -1;
- }
- empty_stats = stats_alloc(pool_datastack_create());
- diff_stats = stats_alloc(pool_datastack_create());
- if (!stats_import(buf->data, buf->used, empty_stats, diff_stats, &error)) {
- *error_r = t_strdup_printf("ADD-USER %s %s: %s",
- user->name, service, error);
- return -1;
- }
- mail_user_refresh(user, diff_stats);
- return 0;
-}
-
-void mail_users_free_memory(void)
-{
- unsigned int diff;
-
- while (mail_users_head != NULL && mail_users_head->refcount == 0) {
- mail_user_free(mail_users_head);
-
- if (global_used_memory < stats_settings->memory_limit ||
- mail_users_head == NULL)
- break;
-
- diff = ioloop_time - mail_users_head->last_update.tv_sec;
- if (diff < stats_settings->user_min_time)
- break;
- }
-}
-
-void mail_users_init(void)
-{
- hash_table_create(&mail_users_hash, default_pool, 0, str_hash, strcmp);
-}
-
-void mail_users_deinit(void)
-{
- while (mail_users_head != NULL)
- mail_user_free(mail_users_head);
- hash_table_destroy(&mail_users_hash);
-}
+++ /dev/null
-#ifndef MAIL_USER_H
-#define MAIL_USER_H
-
-struct stats;
-
-extern struct mail_user *stable_mail_users;
-
-struct mail_user *mail_user_login(const char *username);
-void mail_user_disconnected(struct mail_user *user);
-struct mail_user *mail_user_lookup(const char *username);
-
-void mail_user_refresh(struct mail_user *user,
- const struct stats *diff_stats) ATTR_NULL(2);
-int mail_user_add_parse(const char *const *args, const char **error_r);
-
-void mail_user_ref(struct mail_user *user);
-void mail_user_unref(struct mail_user **user);
-
-void mail_users_free_memory(void);
-void mail_users_init(void);
-void mail_users_deinit(void);
-
-#endif
+++ /dev/null
-/* Copyright (c) 2011-2018 Dovecot authors, see the included COPYING file */
-
-#include "lib.h"
-#include "module-dir.h"
-#include "restrict-access.h"
-#include "master-service.h"
-#include "master-service-settings.h"
-#include "global-memory.h"
-#include "stats-settings.h"
-#include "fifo-input-connection.h"
-#include "mail-command.h"
-#include "mail-session.h"
-#include "mail-user.h"
-#include "mail-domain.h"
-#include "mail-ip.h"
-#include "mail-stats.h"
-#include "client.h"
-
-static struct module *modules = NULL;
-
-static void client_connected(struct master_service_connection *conn)
-{
- if (conn->fifo)
- (void)fifo_input_connection_create(conn->fd);
- else
- (void)client_create(conn->fd);
- master_service_client_connection_accept(conn);
-}
-
-static void main_preinit(void)
-{
- struct module_dir_load_settings mod_set;
-
- i_zero(&mod_set);
- mod_set.abi_version = DOVECOT_ABI_VERSION;
- mod_set.require_init_funcs = TRUE;
-
- modules = module_dir_load(STATS_MODULE_DIR, NULL, &mod_set);
- module_dir_init(modules);
-
- restrict_access_by_env(RESTRICT_ACCESS_FLAG_ALLOW_ROOT, NULL);
- restrict_access_allow_coredumps(TRUE);
-}
-
-int main(int argc, char *argv[])
-{
- const struct setting_parser_info *set_roots[] = {
- &old_stats_setting_parser_info,
- NULL
- };
- const enum master_service_flags service_flags =
- MASTER_SERVICE_FLAG_DONT_SEND_STATS |
- MASTER_SERVICE_FLAG_NO_IDLE_DIE |
- MASTER_SERVICE_FLAG_UPDATE_PROCTITLE;
- const char *error;
- void **sets;
-
- master_service = master_service_init("stats", service_flags,
- &argc, &argv, "");
- if (master_getopt(master_service) > 0)
- return FATAL_DEFAULT;
- if (master_service_settings_read_simple(master_service, set_roots,
- &error) < 0)
- i_fatal("Error reading configuration: %s", error);
- master_service_init_log(master_service);
-
- main_preinit();
-
- sets = master_service_settings_get_others(master_service);
- stats_settings = sets[0];
-
- mail_commands_init();
- mail_sessions_init();
- mail_users_init();
- mail_domains_init();
- mail_ips_init();
- mail_global_init();
-
- master_service_init_finish(master_service);
- master_service_run(master_service, client_connected);
-
- clients_destroy_all();
- fifo_input_connections_destroy_all();
- mail_commands_deinit();
- mail_sessions_deinit();
- mail_users_deinit();
- mail_domains_deinit();
- mail_ips_deinit();
- mail_global_deinit();
-
- module_dir_unload(&modules);
- i_assert(global_used_memory == 0);
- master_service_deinit(&master_service);
- return 0;
-}
+++ /dev/null
-/* Copyright (c) 2011-2018 Dovecot authors, see the included COPYING file */
-
-#include "lib.h"
-#include "ioloop.h"
-#include "time-util.h"
-#include "stats-settings.h"
-#include "mail-stats.h"
-#include "istream.h"
-#include "ostream.h"
-#include "net.h"
-#include "str.h"
-#include "write-full.h"
-#include "stats-carbon.h"
-
-#define CARBON_SERVER_DEFAULT_PORT 2003
-
-struct stats_send_ctx {
- pool_t pool;
- int fd;
- unsigned long to_msecs;
- const char *endpoint;
- const char *str;
- struct io *io;
- struct timeout *to;
-
- void (*callback)(void *);
- void *ctx;
-};
-
-void
-stats_carbon_destroy(struct stats_send_ctx **_ctx)
-{
- struct stats_send_ctx *ctx = *_ctx;
- *_ctx = NULL;
-
- io_remove(&ctx->io);
- timeout_remove(&ctx->to);
- i_close_fd(&ctx->fd);
- pool_unref(&ctx->pool);
-}
-
-static void
-stats_carbon_callback(struct stats_send_ctx *ctx)
-{
- i_assert(ctx->callback != NULL);
- void (*callback)(void *) = ctx->callback;
- ctx->callback = NULL;
- callback(ctx->ctx);
-}
-
-static void
-stats_carbon_timeout(struct stats_send_ctx *ctx)
-{
- i_error("Stats submit(%s) failed: endpoint timeout after %lu msecs",
- ctx->endpoint, ctx->to_msecs);
- stats_carbon_callback(ctx);
-}
-
-static void
-stats_carbon_connected(struct stats_send_ctx *ctx)
-{
- io_remove(&ctx->io);
- if ((errno = net_geterror(ctx->fd)) != 0) {
- i_error("connect(%s) failed: %m",
- ctx->endpoint);
- stats_carbon_callback(ctx);
- return;
- }
- if (write_full(ctx->fd, ctx->str, strlen(ctx->str)) < 0)
- i_error("write(%s) failed: %m",
- ctx->endpoint);
- stats_carbon_callback(ctx);
-}
-
-int
-stats_carbon_send(const char *endpoint, const char *data,
- void (*callback)(void *), void *cb_ctx,
- struct stats_send_ctx **ctx_r)
-{
- const char *host;
- in_port_t port;
- struct ip_addr ip;
-
- if (net_str2hostport(endpoint, CARBON_SERVER_DEFAULT_PORT,
- &host, &port) < 0 ||
- net_addr2ip(host, &ip) < 0) {
- i_error("stats_submit: Cannot parse endpoint '%s'",
- endpoint);
- return -1;
- }
-
- pool_t pool = pool_alloconly_create("stats carbon send", 1024);
- struct stats_send_ctx *ctx = p_new(pool,
- struct stats_send_ctx, 1);
- ctx->pool = pool;
- ctx->str = p_strdup(ctx->pool, data);
-
- ctx->fd = net_connect_ip(&ip, port, NULL);
- if (ctx->fd < 0) {
- i_error("connect(%s) failed: %m", endpoint);
- stats_carbon_callback(ctx);
- return -1;
- }
- ctx->io = io_add(ctx->fd, IO_WRITE,
- stats_carbon_connected,
- ctx);
-
- /* give time for almost until next update
- this is to ensure we leave a little pause between
- attempts. Multiplier 800 gives us 20% window, and
- ensures the number stays positive. */
- ctx->to_msecs = stats_settings->carbon_interval*800;
- ctx->to = timeout_add(ctx->to_msecs,
- stats_carbon_timeout,
- ctx);
- ctx->endpoint = p_strdup(ctx->pool, net_ipport2str(&ip, port));
- ctx->callback = callback;
- ctx->ctx = cb_ctx;
-
- *ctx_r = ctx;
-
- return 0;
-}
+++ /dev/null
-#ifndef STATS_CARBON
-#define STATS_CARBON 1
-
-struct stats_send_ctx;
-
-int
-stats_carbon_send(const char *endpoint, const char *data,
- void (*callback)(void *), void *cb_ctx,
- struct stats_send_ctx **ctx_r);
-void
-stats_carbon_destroy(struct stats_send_ctx **ctx);
-
-#endif
+++ /dev/null
-/* Copyright (c) 2009-2018 Dovecot authors, see the included COPYING file */
-
-#include "lib.h"
-#include "buffer.h"
-#include "settings-parser.h"
-#include "service-settings.h"
-#include "stats-settings.h"
-
-/* <settings checks> */
-static struct file_listener_settings old_stats_unix_listeners_array[] = {
- { "old-stats", 0600, "", "" }
-};
-static struct file_listener_settings *old_stats_unix_listeners[] = {
- &old_stats_unix_listeners_array[0]
-};
-static buffer_t old_stats_unix_listeners_buf = {
- { { old_stats_unix_listeners, sizeof(old_stats_unix_listeners) } }
-};
-static struct file_listener_settings old_stats_fifo_listeners_array[] = {
- { "old-stats-mail", 0600, "", "" },
- { "old-stats-user", 0600, "", "" }
-};
-static struct file_listener_settings *old_stats_fifo_listeners[] = {
- &old_stats_fifo_listeners_array[0],
- &old_stats_fifo_listeners_array[1]
-};
-static buffer_t old_stats_fifo_listeners_buf = {
- { { old_stats_fifo_listeners, sizeof(old_stats_fifo_listeners) } }
-};
-/* </settings checks> */
-
-struct service_settings old_stats_service_settings = {
- .name = "old-stats",
- .protocol = "",
- .type = "",
- .executable = "old-stats",
- .user = "$default_internal_user",
- .group = "",
- .privileged_group = "",
- .extra_groups = "",
- .chroot = "empty",
-
- .drop_priv_before_exec = FALSE,
-
- .process_min_avail = 0,
- .process_limit = 1,
- .client_limit = 0,
- .service_count = 0,
- .idle_kill = UINT_MAX,
- .vsz_limit = UOFF_T_MAX,
-
- .unix_listeners = { { &old_stats_unix_listeners_buf,
- sizeof(old_stats_unix_listeners[0]) } },
- .fifo_listeners = { { &old_stats_fifo_listeners_buf,
- sizeof(old_stats_fifo_listeners[0]) } },
- .inet_listeners = ARRAY_INIT,
-
- .process_limit_1 = TRUE
-};
-
-/* we're kind of kludging here to avoid "stats_" prefix in the struct fields */
-#undef DEF
-#define DEF(type, name) \
- SETTING_DEFINE_STRUCT_##type("old_stats_"#name, name, struct old_stats_settings)
-
-static const struct setting_define old_stats_setting_defines[] = {
- DEF(SIZE, memory_limit),
- DEF(TIME, command_min_time),
- DEF(TIME, session_min_time),
- DEF(TIME, user_min_time),
- DEF(TIME, domain_min_time),
- DEF(TIME, ip_min_time),
- DEF(STR, carbon_server),
- DEF(TIME, carbon_interval),
- DEF(STR, carbon_name),
- SETTING_DEFINE_LIST_END
-};
-
-const struct old_stats_settings old_stats_default_settings = {
- .memory_limit = 1024*1024*16,
-
- .command_min_time = 60,
- .session_min_time = 60*15,
- .user_min_time = 60*60,
- .domain_min_time = 60*60*12,
- .ip_min_time = 60*60*12,
-
- .carbon_interval = 30,
- .carbon_server = "",
- .carbon_name = ""
-};
-
-const struct setting_parser_info old_stats_setting_parser_info = {
- .module_name = "stats",
- .defines = old_stats_setting_defines,
- .defaults = &old_stats_default_settings,
-
- .type_offset = SIZE_MAX,
- .struct_size = sizeof(struct old_stats_settings),
-
- .parent_offset = SIZE_MAX
-};
-
-const struct old_stats_settings *stats_settings;
+++ /dev/null
-#ifndef STATS_SETTINGS_H
-#define STATS_SETTINGS_H
-
-struct old_stats_settings {
- uoff_t memory_limit;
-
- unsigned int command_min_time;
- unsigned int session_min_time;
- unsigned int user_min_time;
- unsigned int domain_min_time;
- unsigned int ip_min_time;
-
- unsigned int carbon_interval;
- const char *carbon_server;
- const char *carbon_name;
-};
-
-extern const struct setting_parser_info old_stats_setting_parser_info;
-extern const struct old_stats_settings *stats_settings;
-
-#endif
-
imap-quota \
pop3-migration \
replication \
- old-stats \
- imap-old-stats \
mail-crypt \
trash \
virtual \
+++ /dev/null
-AM_CPPFLAGS = \
- -I$(top_srcdir)/src/lib \
- -I$(top_srcdir)/src/lib-old-stats \
- -I$(top_srcdir)/src/lib-mail \
- -I$(top_srcdir)/src/lib-imap \
- -I$(top_srcdir)/src/lib-index \
- -I$(top_srcdir)/src/lib-storage \
- -I$(top_srcdir)/src/imap \
- -I$(top_srcdir)/src/plugins/old-stats
-
-imap_moduledir = $(moduledir)
-
-NOPLUGIN_LDFLAGS =
-lib95_imap_old_stats_plugin_la_LDFLAGS = -module -avoid-version
-
-imap_module_LTLIBRARIES = \
- lib95_imap_old_stats_plugin.la
-
-if DOVECOT_PLUGIN_DEPS
-lib95_imap_old_stats_plugin_la_LIBADD = \
- ../old-stats/lib90_old_stats_plugin.la
-endif
-
-lib95_imap_old_stats_plugin_la_SOURCES = \
- imap-stats-plugin.c
-
-noinst_HEADERS = \
- imap-stats-plugin.h
+++ /dev/null
-/* Copyright (c) 2011-2018 Dovecot authors, see the included COPYING file */
-
-#include "imap-common.h"
-#include "base64.h"
-#include "str.h"
-#include "imap-commands.h"
-#include "stats.h"
-#include "stats-plugin.h"
-#include "stats-connection.h"
-#include "imap-stats-plugin.h"
-
-#define IMAP_STATS_IMAP_CONTEXT(obj) \
- MODULE_CONTEXT(obj, imap_stats_imap_module)
-
-struct stats_client_command {
- union imap_module_context module_ctx;
-
- unsigned int id;
- bool continued;
- struct stats *stats, *pre_stats;
-};
-
-static MODULE_CONTEXT_DEFINE_INIT(imap_stats_imap_module,
- &imap_module_register);
-
-const char *imap_stats_plugin_version = DOVECOT_ABI_VERSION;
-
-static void stats_command_pre(struct client_command_context *cmd)
-{
- struct stats_user *suser = STATS_USER_CONTEXT(cmd->client->user);
- struct stats_client_command *scmd;
- static unsigned int stats_cmd_id_counter = 0;
-
- if (suser == NULL || !suser->track_commands)
- return;
-
- if (strcasecmp(cmd->name, "IDLE") == 0) {
- /* IDLE can run forever and waste stats process's memory while
- waiting for it to timeout. don't send them. */
- return;
- }
-
- scmd = IMAP_STATS_IMAP_CONTEXT(cmd);
- if (scmd == NULL) {
- scmd = p_new(cmd->pool, struct stats_client_command, 1);
- scmd->id = ++stats_cmd_id_counter;
- scmd->stats = stats_alloc(cmd->pool);
- scmd->pre_stats = stats_alloc(cmd->pool);
- MODULE_CONTEXT_SET(cmd, imap_stats_imap_module, scmd);
- }
-
- mail_user_stats_fill(cmd->client->user, scmd->pre_stats);
-}
-
-static void stats_command_post(struct client_command_context *cmd)
-{
- struct stats_user *suser = STATS_USER_CONTEXT(cmd->client->user);
- struct stats_client_command *scmd = IMAP_STATS_IMAP_CONTEXT(cmd);
- struct stats *new_stats, *diff_stats;
- const char *error;
- size_t args_pos = 0, args_len = 0;
- string_t *str;
- buffer_t *buf;
-
- if (suser == NULL || scmd == NULL)
- return;
-
- new_stats = stats_alloc(pool_datastack_create());
- diff_stats = stats_alloc(pool_datastack_create());
-
- mail_user_stats_fill(cmd->client->user, new_stats);
- if (!stats_diff(scmd->pre_stats, new_stats, diff_stats, &error))
- i_error("stats: command stats shrank: %s", error);
- stats_add(scmd->stats, diff_stats);
-
- str = t_str_new(128);
- str_append(str, "UPDATE-CMD\t");
- str_append(str, suser->stats_session_id);
-
- str_printfa(str, "\t%u\t", scmd->id);
- if (cmd->state == CLIENT_COMMAND_STATE_DONE)
- str_append_c(str, 'd');
- if (scmd->continued)
- str_append_c(str, 'c');
- else {
- str_append_c(str, '\t');
- str_append(str, cmd->name);
- str_append_c(str, '\t');
- args_pos = str_len(str);
- if (cmd->args != NULL)
- str_append(str, cmd->args);
- args_len = str_len(str) - args_pos;
- scmd->continued = TRUE;
- }
-
- buf = t_buffer_create(128);
- stats_export(buf, scmd->stats);
- str_append_c(str, '\t');
- base64_encode(buf->data, buf->used, str);
-
- str_append_c(str, '\n');
-
- if (str_len(str) > PIPE_BUF) {
- /* truncate the args so it fits */
- size_t delete_count = str_len(str) - PIPE_BUF;
-
- i_assert(args_pos != 0);
- if (delete_count > args_len)
- delete_count = args_len;
- str_delete(str, args_pos + args_len - delete_count,
- delete_count);
- }
-
- stats_connection_send(suser->stats_conn, str);
-}
-
-void imap_old_stats_plugin_init(struct module *module ATTR_UNUSED)
-{
- command_hook_register(stats_command_pre, stats_command_post);
-}
-
-void imap_old_stats_plugin_deinit(void)
-{
- command_hook_unregister(stats_command_pre, stats_command_post);
-}
-
-const char *imap_old_stats_plugin_dependencies[] = { "old_stats", NULL };
-const char imap_old_stats_plugin_binary_dependency[] = "imap";
+++ /dev/null
-#ifndef IMAP_STATS_PLUGIN_H
-#define IMAP_STATS_PLUGIN_H
-
-struct module;
-
-extern const char *imap_stats_plugin_dependencies[];
-extern const char imap_stats_plugin_binary_dependency[];
-
-void imap_old_stats_plugin_init(struct module *module);
-void imap_old_stats_plugin_deinit(void);
-
-#endif
+++ /dev/null
-AM_CPPFLAGS = \
- -I$(top_srcdir)/src/lib \
- -I$(top_srcdir)/src/lib-settings \
- -I$(top_srcdir)/src/lib-mail \
- -I$(top_srcdir)/src/lib-master \
- -I$(top_srcdir)/src/lib-old-stats \
- -I$(top_srcdir)/src/lib-index \
- -I$(top_srcdir)/src/lib-storage
-
-NOPLUGIN_LDFLAGS =
-lib90_old_stats_plugin_la_LDFLAGS = -module -avoid-version
-
-module_LTLIBRARIES = \
- lib90_old_stats_plugin.la
-
-lib90_old_stats_plugin_la_SOURCES = \
- mail-stats.c \
- mail-stats-fill.c \
- mail-stats-connection.c \
- stats-plugin.c
-
-noinst_HEADERS = \
- mail-stats.h \
- mail-stats-connection.h \
- stats-plugin.h
-
-old_stats_moduledir = $(moduledir)/old-stats
-old_stats_module_LTLIBRARIES = libold_stats_mail.la
-
-libold_stats_mail_la_LDFLAGS = -module -avoid-version
-libold_stats_mail_la_LIBADD = mail-stats.lo $(LIBDOVECOT)
-libold_stats_mail_la_DEPENDENCIES = mail-stats.lo
-libold_stats_mail_la_SOURCES =
+++ /dev/null
-/* Copyright (c) 2011-2018 Dovecot authors, see the included COPYING file */
-
-#include "lib.h"
-#include "base64.h"
-#include "hostpid.h"
-#include "net.h"
-#include "str.h"
-#include "strescape.h"
-#include "mail-storage.h"
-#include "stats.h"
-#include "stats-plugin.h"
-#include "mail-stats-connection.h"
-
-int mail_stats_connection_connect(struct stats_connection *conn,
- struct mail_user *user)
-{
- struct stats_user *suser = STATS_USER_CONTEXT_REQUIRE(user);
- string_t *str = t_str_new(128);
-
- str_append(str, "CONNECT\t");
- /* required fields */
- str_append(str, suser->stats_session_id);
- str_append_c(str, '\t');
- str_append_tabescaped(str, user->username);
- str_append_c(str, '\t');
- str_append_tabescaped(str, user->service);
- str_printfa(str, "\t%s", my_pid);
-
- /* optional fields */
- if (user->conn.local_ip != NULL) {
- str_append(str, "\tlip=");
- str_append(str, net_ip2addr(user->conn.local_ip));
- }
- if (user->conn.remote_ip != NULL) {
- str_append(str, "\trip=");
- str_append(str, net_ip2addr(user->conn.remote_ip));
- }
- str_append_c(str, '\n');
- return stats_connection_send(conn, str);
-}
-
-void mail_stats_connection_disconnect(struct stats_connection *conn,
- struct mail_user *user)
-{
- struct stats_user *suser = STATS_USER_CONTEXT_REQUIRE(user);
- string_t *str = t_str_new(128);
-
- str_append(str, "DISCONNECT\t");
- str_append(str, suser->stats_session_id);
- str_append_c(str, '\n');
- if (stats_connection_send(conn, str) < 0) {
- /* we could retry this later, but stats process will forget it
- anyway after 15 minutes. */
- }
-}
-
-void mail_stats_connection_send_session(struct stats_connection *conn,
- struct mail_user *user,
- const struct stats *stats)
-{
- struct stats_user *suser = STATS_USER_CONTEXT_REQUIRE(user);
- string_t *str = t_str_new(256);
- buffer_t *buf;
-
- buf = t_buffer_create(128);
- stats_export(buf, stats);
-
- str_append(str, "UPDATE-SESSION\t");
- str_append(str, suser->stats_session_id);
- str_append_c(str, '\t');
- base64_encode(buf->data, buf->used, str);
-
- str_append_c(str, '\n');
- (void)stats_connection_send(conn, str);
-}
+++ /dev/null
-#ifndef MAIL_STATS_CONNECTION_H
-#define MAIL_STATS_CONNECTION_H
-
-#include "stats-connection.h"
-
-struct mail_stats;
-struct mail_user;
-
-int mail_stats_connection_connect(struct stats_connection *conn,
- struct mail_user *user);
-void mail_stats_connection_disconnect(struct stats_connection *conn,
- struct mail_user *user);
-
-void mail_stats_connection_send_session(struct stats_connection *conn,
- struct mail_user *user,
- const struct stats *stats);
-void mail_stats_connection_send(struct stats_connection *conn, const string_t *str);
-
-#endif
+++ /dev/null
-/* Copyright (c) 2011-2018 Dovecot authors, see the included COPYING file */
-
-#include "lib.h"
-#include "time-util.h"
-#include "stats-plugin.h"
-#include "mail-stats.h"
-
-#include <sys/resource.h>
-
-#define PROC_IO_PATH "/proc/self/io"
-
-static bool proc_io_disabled = FALSE;
-static int proc_io_fd = -1;
-
-static int
-process_io_buffer_parse(const char *buf, struct mail_stats *stats)
-{
- const char *const *tmp;
-
- tmp = t_strsplit(buf, "\n");
- for (; *tmp != NULL; tmp++) {
- if (str_begins(*tmp, "rchar: ")) {
- if (str_to_uint64(*tmp + 7, &stats->read_bytes) < 0)
- return -1;
- } else if (str_begins(*tmp, "wchar: ")) {
- if (str_to_uint64(*tmp + 7, &stats->write_bytes) < 0)
- return -1;
- } else if (str_begins(*tmp, "syscr: ")) {
- if (str_to_uint32(*tmp + 7, &stats->read_count) < 0)
- return -1;
- } else if (str_begins(*tmp, "syscw: ")) {
- if (str_to_uint32(*tmp + 7, &stats->write_count) < 0)
- return -1;
- }
- }
- return 0;
-}
-
-static int process_io_open(void)
-{
- uid_t uid;
-
- if (proc_io_fd != -1)
- return proc_io_fd;
-
- if (proc_io_disabled)
- return -1;
-
- proc_io_fd = open(PROC_IO_PATH, O_RDONLY);
- if (proc_io_fd == -1 && errno == EACCES) {
- /* kludge: if we're running with permissions temporarily
- dropped, get them temporarily back so we can open
- /proc/self/io. */
- uid = geteuid();
- if (seteuid(0) == 0) {
- proc_io_fd = open(PROC_IO_PATH, O_RDONLY);
- if (seteuid(uid) < 0) {
- /* oops, this is bad */
- i_fatal("stats: seteuid(%s) failed", dec2str(uid));
- }
- }
- errno = EACCES;
- }
- if (proc_io_fd == -1) {
- /* ignore access errors too, certain security options can
- prevent root access to this file when not owned by root */
- if (errno != ENOENT && errno != EACCES)
- i_error("open(%s) failed: %m", PROC_IO_PATH);
- proc_io_disabled = TRUE;
- return -1;
- }
- return proc_io_fd;
-}
-
-static void process_read_io_stats(struct mail_stats *stats)
-{
- char buf[1024];
- int fd, ret;
-
- if ((fd = process_io_open()) == -1)
- return;
-
- ret = pread(fd, buf, sizeof(buf), 0);
- if (ret <= 0) {
- if (ret == -1)
- i_error("read(%s) failed: %m", PROC_IO_PATH);
- else
- i_error("read(%s) returned EOF", PROC_IO_PATH);
- } else if (ret == sizeof(buf)) {
- /* just shouldn't happen.. */
- i_error("%s is larger than expected", PROC_IO_PATH);
- proc_io_disabled = TRUE;
- } else {
- buf[ret] = '\0';
- T_BEGIN {
- if (process_io_buffer_parse(buf, stats) < 0) {
- i_error("Invalid input in file %s",
- PROC_IO_PATH);
- proc_io_disabled = TRUE;
- }
- } T_END;
- }
-}
-
-static void
-user_trans_stats_get(struct stats_user *suser, struct mail_stats *dest_r)
-{
- struct stats_transaction_context *strans;
-
- mail_stats_add_transaction(dest_r, &suser->finished_transaction_stats);
- for (strans = suser->transactions; strans != NULL; strans = strans->next)
- mail_stats_add_transaction(dest_r, &strans->trans->stats);
-}
-
-void mail_stats_fill(struct stats_user *suser, struct mail_stats *stats_r)
-{
- static bool getrusage_broken = FALSE;
- static struct rusage prev_usage;
- struct rusage usage;
-
- i_zero(stats_r);
- /* cputime */
- if (getrusage(RUSAGE_SELF, &usage) < 0) {
- if (!getrusage_broken) {
- i_error("getrusage() failed: %m");
- getrusage_broken = TRUE;
- }
- usage = prev_usage;
- } else if (timeval_diff_usecs(&usage.ru_stime, &prev_usage.ru_stime) < 0) {
- /* This seems to be a Linux bug. */
- usage.ru_stime = prev_usage.ru_stime;
- }
- prev_usage = usage;
-
- stats_r->user_cpu = usage.ru_utime;
- stats_r->sys_cpu = usage.ru_stime;
- stats_r->min_faults = usage.ru_minflt;
- stats_r->maj_faults = usage.ru_majflt;
- stats_r->vol_cs = usage.ru_nvcsw;
- stats_r->invol_cs = usage.ru_nivcsw;
- stats_r->disk_input = (unsigned long long)usage.ru_inblock * 512ULL;
- stats_r->disk_output = (unsigned long long)usage.ru_oublock * 512ULL;
- i_gettimeofday(&stats_r->clock_time);
- process_read_io_stats(stats_r);
- user_trans_stats_get(suser, stats_r);
-}
-
-void mail_stats_global_preinit(void)
-{
- (void)process_io_open();
-}
-
-void mail_stats_fill_global_deinit(void)
-{
- i_close_fd(&proc_io_fd);
-}
+++ /dev/null
-/* Copyright (c) 2011-2018 Dovecot authors, see the included COPYING file */
-
-#include "lib.h"
-#include "time-util.h"
-#include "stats.h"
-#include "stats-parser.h"
-#include "mail-stats.h"
-
-static struct stats_parser_field mail_stats_fields[] = {
-#define E(parsename, name, type) { parsename, offsetof(struct mail_stats, name), sizeof(((struct mail_stats *)0)->name), type }
-#define EN(parsename, name) E(parsename, name, STATS_PARSER_TYPE_UINT)
- E("user_cpu", user_cpu, STATS_PARSER_TYPE_TIMEVAL),
- E("sys_cpu", sys_cpu, STATS_PARSER_TYPE_TIMEVAL),
- E("clock_time", clock_time, STATS_PARSER_TYPE_TIMEVAL),
- EN("min_faults", min_faults),
- EN("maj_faults", maj_faults),
- EN("vol_cs", vol_cs),
- EN("invol_cs", invol_cs),
- EN("disk_input", disk_input),
- EN("disk_output", disk_output),
-
- EN("read_count", read_count),
- EN("read_bytes", read_bytes),
- EN("write_count", write_count),
- EN("write_bytes", write_bytes),
-
- /*EN("mopen", trans_stats.open_lookup_count),
- EN("mstat", trans_stats.stat_lookup_count),
- EN("mfstat", trans_stats.fstat_lookup_count),*/
- EN("mail_lookup_path", trans_lookup_path),
- EN("mail_lookup_attr", trans_lookup_attr),
- EN("mail_read_count", trans_files_read_count),
- EN("mail_read_bytes", trans_files_read_bytes),
- EN("mail_cache_hits", trans_cache_hit_count)
-};
-
-static size_t mail_stats_alloc_size(void)
-{
- return sizeof(struct mail_stats);
-}
-
-static unsigned int mail_stats_field_count(void)
-{
- return N_ELEMENTS(mail_stats_fields);
-}
-
-static const char *mail_stats_field_name(unsigned int n)
-{
- i_assert(n < N_ELEMENTS(mail_stats_fields));
-
- return mail_stats_fields[n].name;
-}
-
-static void
-mail_stats_field_value(string_t *str, const struct stats *stats,
- unsigned int n)
-{
- i_assert(n < N_ELEMENTS(mail_stats_fields));
-
- stats_parser_value(str, &mail_stats_fields[n], stats);
-}
-
-static bool
-mail_stats_diff(const struct stats *stats1, const struct stats *stats2,
- struct stats *diff_stats_r, const char **error_r)
-{
- return stats_parser_diff(mail_stats_fields, N_ELEMENTS(mail_stats_fields),
- stats1, stats2, diff_stats_r, error_r);
-}
-
-static void mail_stats_add(struct stats *dest, const struct stats *src)
-{
- stats_parser_add(mail_stats_fields, N_ELEMENTS(mail_stats_fields),
- dest, src);
-}
-
-static bool
-mail_stats_have_changed(const struct stats *_prev, const struct stats *_cur)
-{
- const struct mail_stats *prev = (const struct mail_stats *)_prev;
- const struct mail_stats *cur = (const struct mail_stats *)_cur;
-
- if (cur->disk_input != prev->disk_input ||
- cur->disk_output != prev->disk_output ||
- cur->trans_lookup_path != prev->trans_lookup_path ||
- cur->trans_lookup_attr != prev->trans_lookup_attr ||
- cur->trans_files_read_count != prev->trans_files_read_count ||
- cur->trans_files_read_bytes != prev->trans_files_read_bytes ||
- cur->trans_cache_hit_count != prev->trans_cache_hit_count)
- return TRUE;
-
- /* allow a tiny bit of changes that are caused by this
- timeout handling */
- if (timeval_diff_msecs(&cur->user_cpu, &prev->user_cpu) != 0)
- return TRUE;
- if (timeval_diff_msecs(&cur->sys_cpu, &prev->sys_cpu) != 0)
- return TRUE;
-
- if (cur->maj_faults > prev->maj_faults+10)
- return TRUE;
- if (cur->invol_cs > prev->invol_cs+10)
- return TRUE;
- /* don't check for read/write count/bytes changes, since they get
- changed by stats checking itself */
- return FALSE;
-}
-
-static void mail_stats_export(buffer_t *buf, const struct stats *_stats)
-{
- const struct mail_stats *stats = (const struct mail_stats *)_stats;
-
- buffer_append(buf, stats, sizeof(*stats));
-}
-
-static bool
-mail_stats_import(const unsigned char *data, size_t size, size_t *pos_r,
- struct stats *_stats, const char **error_r)
-{
- struct mail_stats *stats = (struct mail_stats *)_stats;
-
- if (size < sizeof(*stats)) {
- *error_r = "mail_stats too small";
- return FALSE;
- }
- memcpy(stats, data, sizeof(*stats));
- *pos_r = sizeof(*stats);
- return TRUE;
-}
-
-void mail_stats_add_transaction(struct mail_stats *stats,
- const struct mailbox_transaction_stats *trans_stats)
-{
- stats->trans_lookup_path += trans_stats->open_lookup_count;
- stats->trans_lookup_attr += trans_stats->stat_lookup_count +
- trans_stats->fstat_lookup_count;
- stats->trans_files_read_count += trans_stats->files_read_count;
- stats->trans_files_read_bytes += trans_stats->files_read_bytes;
- stats->trans_cache_hit_count += trans_stats->cache_hit_count;
-}
-
-const struct stats_vfuncs mail_stats_vfuncs = {
- "mail",
- mail_stats_alloc_size,
- mail_stats_field_count,
- mail_stats_field_name,
- mail_stats_field_value,
- mail_stats_diff,
- mail_stats_add,
- mail_stats_have_changed,
- mail_stats_export,
- mail_stats_import
-};
-
-/* for the stats_mail plugin: */
-void old_stats_mail_init(void);
-void old_stats_mail_deinit(void);
-
-static struct stats_item *mail_stats_item;
-
-void old_stats_mail_init(void)
-{
- mail_stats_item = stats_register(&mail_stats_vfuncs);
-}
-
-void old_stats_mail_deinit(void)
-{
- stats_unregister(&mail_stats_item);
-}
+++ /dev/null
-#ifndef MAIL_STATS_H
-#define MAIL_STATS_H
-
-#include <sys/time.h>
-#include "mail-storage-private.h"
-
-struct stats_user;
-
-struct mail_stats {
- /* user/system CPU time used */
- struct timeval user_cpu, sys_cpu;
- /* clock time used (not counting the time in ioloop wait) */
- struct timeval clock_time;
- /* minor / major page faults */
- uint32_t min_faults, maj_faults;
- /* voluntary / involuntary context switches */
- uint32_t vol_cs, invol_cs;
- /* disk input/output bytes */
- uint64_t disk_input, disk_output;
- /* read()/write() syscall count and number of bytes */
- uint32_t read_count, write_count;
- uint64_t read_bytes, write_bytes;
-
- /* based on struct mailbox_transaction_stats: */
- uint32_t trans_lookup_path;
- uint32_t trans_lookup_attr;
- uint32_t trans_files_read_count;
- uint64_t trans_files_read_bytes;
- uint64_t trans_cache_hit_count;
-};
-
-extern const struct stats_vfuncs mail_stats_vfuncs;
-
-void mail_stats_fill(struct stats_user *suser, struct mail_stats *mail_stats);
-void mail_stats_add_transaction(struct mail_stats *stats,
- const struct mailbox_transaction_stats *trans_stats);
-
-void mail_stats_global_preinit(void);
-void mail_stats_fill_global_deinit(void);
-
-#endif
+++ /dev/null
-/* Copyright (c) 2011-2018 Dovecot authors, see the included COPYING file */
-
-#include "lib.h"
-#include "ioloop.h"
-#include "llist.h"
-#include "str.h"
-#include "time-util.h"
-#include "settings-parser.h"
-#include "mail-stats.h"
-#include "stats.h"
-#include "mail-stats-connection.h"
-#include "stats-plugin.h"
-
-#define STATS_CONTEXT(obj) \
- MODULE_CONTEXT(obj, stats_storage_module)
-#define STATS_CONTEXT_REQUIRE(obj) \
- MODULE_CONTEXT_REQUIRE(obj, stats_storage_module)
-
-/* If session isn't refreshed every 15 minutes, it's dropped.
- Must be smaller than MAIL_SESSION_IDLE_TIMEOUT_MSECS in stats server */
-#define SESSION_STATS_FORCE_REFRESH_SECS (5*60)
-#define REFRESH_CHECK_INTERVAL 100
-#define MAIL_STATS_FIFO_NAME "old-stats-mail"
-
-struct stats_storage {
- union mail_storage_module_context module_ctx;
-
- struct mail_storage_callbacks old_callbacks;
- void *old_context;
-};
-
-struct stats_mailbox {
- union mailbox_module_context module_ctx;
-};
-
-const char *stats_plugin_version = DOVECOT_ABI_VERSION;
-
-struct stats_user_module stats_user_module =
- MODULE_CONTEXT_INIT(&mail_user_module_register);
-struct stats_storage_module stats_storage_module =
- MODULE_CONTEXT_INIT(&mail_storage_module_register);
-
-static struct stats_item *mail_stats_item;
-static struct stats_connection *global_stats_conn = NULL;
-static struct mail_user *stats_global_user = NULL;
-static unsigned int stats_user_count = 0;
-
-static void session_stats_refresh_timeout(struct mail_user *user);
-
-static void stats_io_activate(struct mail_user *user)
-{
- struct stats_user *suser = STATS_USER_CONTEXT_REQUIRE(user);
- struct mail_stats *mail_stats;
-
- if (stats_user_count == 1) {
- /* the first user sets the global user. the second user sets
- it to NULL. when we get back to one user we'll need to set
- the global user again somewhere. do it here. */
- stats_global_user = user;
- /* skip time spent waiting in ioloop */
- mail_stats = stats_fill_ptr(suser->pre_io_stats, mail_stats_item);
- mail_stats->clock_time = ioloop_timeval;
- } else {
- i_assert(stats_global_user == NULL);
-
- mail_user_stats_fill(user, suser->pre_io_stats);
- }
-}
-
-static void stats_add_session(struct mail_user *user)
-{
- struct stats_user *suser = STATS_USER_CONTEXT_REQUIRE(user);
- struct stats *new_stats, *diff_stats;
- const char *error;
-
- new_stats = stats_alloc(pool_datastack_create());
- diff_stats = stats_alloc(pool_datastack_create());
-
- mail_user_stats_fill(user, new_stats);
- /* we'll count new_stats-pre_io_stats and add the changes to
- session_stats. the new_stats can't be directly copied to
- session_stats because there are some fields that don't start from
- zero, like clock_time. (actually with stats_global_user code we're
- requiring that clock_time is the only such field..) */
- if (!stats_diff(suser->pre_io_stats, new_stats, diff_stats, &error))
- i_error("stats: session stats shrank: %s", error);
- stats_add(suser->session_stats, diff_stats);
- /* copying is only needed if stats_global_user=NULL */
- stats_copy(suser->pre_io_stats, new_stats);
-}
-
-static bool
-session_stats_need_send(struct stats_user *suser, time_t now,
- bool *changed_r, unsigned int *to_next_secs_r)
-{
- unsigned int diff;
-
- *to_next_secs_r = SESSION_STATS_FORCE_REFRESH_SECS;
-
- if (stats_have_changed(suser->last_sent_session_stats,
- suser->session_stats)) {
- *to_next_secs_r = suser->refresh_secs;
- *changed_r = TRUE;
- return TRUE;
- }
- *changed_r = FALSE;
-
- diff = now - suser->last_session_update;
- if (diff >= SESSION_STATS_FORCE_REFRESH_SECS)
- return TRUE;
- *to_next_secs_r = SESSION_STATS_FORCE_REFRESH_SECS - diff;
-
- if (!suser->session_sent_duplicate) {
- if (suser->last_session_update != now) {
- /* send one duplicate notification so stats reader
- knows that this session is idle now */
- return TRUE;
- }
- }
- return FALSE;
-}
-
-static void session_stats_refresh(struct mail_user *user)
-{
- struct stats_user *suser = STATS_USER_CONTEXT_REQUIRE(user);
- unsigned int to_next_secs;
- time_t now = time(NULL);
- bool changed;
-
- if (!suser->stats_connected) {
- if (mail_stats_connection_connect(suser->stats_conn, user) == 0)
- suser->stats_connected = TRUE;
- }
- if (session_stats_need_send(suser, now, &changed, &to_next_secs) &&
- suser->stats_connected) {
- suser->session_sent_duplicate = !changed;
- suser->last_session_update = now;
- stats_copy(suser->last_sent_session_stats, suser->session_stats);
- mail_stats_connection_send_session(suser->stats_conn, user,
- suser->session_stats);
- }
-
- timeout_remove(&suser->to_stats_timeout);
- suser->to_stats_timeout =
- timeout_add(to_next_secs*1000,
- session_stats_refresh_timeout, user);
-}
-
-static struct mailbox_transaction_context *
-stats_transaction_begin(struct mailbox *box,
- enum mailbox_transaction_flags flags,
- const char *reason)
-{
- struct stats_user *suser = STATS_USER_CONTEXT_REQUIRE(box->storage->user);
- struct stats_mailbox *sbox = STATS_CONTEXT_REQUIRE(box);
- struct mailbox_transaction_context *trans;
- struct stats_transaction_context *strans;
-
- trans = sbox->module_ctx.super.transaction_begin(box, flags, reason);
- trans->stats_track = TRUE;
-
- strans = i_new(struct stats_transaction_context, 1);
- strans->trans = trans;
- DLLIST_PREPEND(&suser->transactions, strans);
-
- MODULE_CONTEXT_SET(trans, stats_storage_module, strans);
- return trans;
-}
-
-static void stats_transaction_free(struct stats_user *suser,
- struct stats_transaction_context *strans)
-{
- const struct mailbox_transaction_stats *src = &strans->trans->stats;
- struct mailbox_transaction_stats *dest =
- &suser->finished_transaction_stats;
-
- DLLIST_REMOVE(&suser->transactions, strans);
-
- dest->open_lookup_count += src->open_lookup_count;
- dest->stat_lookup_count += src->stat_lookup_count;
- dest->fstat_lookup_count += src->fstat_lookup_count;
- dest->files_read_count += src->files_read_count;
- dest->files_read_bytes += src->files_read_bytes;
- dest->cache_hit_count += src->cache_hit_count;
- i_free(strans);
-}
-
-static int
-stats_transaction_commit(struct mailbox_transaction_context *ctx,
- struct mail_transaction_commit_changes *changes_r)
-{
- struct stats_transaction_context *strans = STATS_CONTEXT_REQUIRE(ctx);
- struct stats_mailbox *sbox = STATS_CONTEXT_REQUIRE(ctx->box);
- struct stats_user *suser = STATS_USER_CONTEXT_REQUIRE(ctx->box->storage->user);
-
- stats_transaction_free(suser, strans);
- return sbox->module_ctx.super.transaction_commit(ctx, changes_r);
-}
-
-static void
-stats_transaction_rollback(struct mailbox_transaction_context *ctx)
-{
- struct stats_transaction_context *strans = STATS_CONTEXT_REQUIRE(ctx);
- struct stats_mailbox *sbox = STATS_CONTEXT_REQUIRE(ctx->box);
- struct stats_user *suser = STATS_USER_CONTEXT_REQUIRE(ctx->box->storage->user);
-
- stats_transaction_free(suser, strans);
- sbox->module_ctx.super.transaction_rollback(ctx);
-}
-
-static bool stats_search_next_nonblock(struct mail_search_context *ctx,
- struct mail **mail_r, bool *tryagain_r)
-{
- struct stats_mailbox *sbox = STATS_CONTEXT_REQUIRE(ctx->transaction->box);
- struct mail_user *user = ctx->transaction->box->storage->user;
- struct stats_user *suser = STATS_USER_CONTEXT_REQUIRE(user);
- bool ret;
-
- ret = sbox->module_ctx.super.
- search_next_nonblock(ctx, mail_r, tryagain_r);
- if (!ret && !*tryagain_r) {
- /* end of search */
- return FALSE;
- }
-
- if (*tryagain_r ||
- ++suser->refresh_check_counter % REFRESH_CHECK_INTERVAL == 0) {
- /* a) retrying, so this is a long running search.
- b) we've returned enough matches */
- if (time(NULL) != suser->last_session_update)
- session_stats_refresh(user);
- }
- return ret;
-}
-
-static void
-stats_notify_ok(struct mailbox *box, const char *text, void *context)
-{
- struct stats_storage *sstorage = STATS_CONTEXT_REQUIRE(box->storage);
-
- /* most importantly we want to refresh stats for very long running
- mailbox syncs */
- session_stats_refresh(box->storage->user);
-
- if (sstorage->old_callbacks.notify_ok != NULL)
- sstorage->old_callbacks.notify_ok(box, text, context);
-}
-
-static void stats_register_notify_callbacks(struct mail_storage *storage)
-{
- struct stats_storage *sstorage = STATS_CONTEXT(storage);
-
- if (sstorage != NULL)
- return;
-
- sstorage = p_new(storage->pool, struct stats_storage, 1);
- sstorage->old_callbacks = storage->callbacks;
- storage->callbacks.notify_ok = stats_notify_ok;
-
- MODULE_CONTEXT_SET(storage, stats_storage_module, sstorage);
-}
-
-static void stats_mailbox_allocated(struct mailbox *box)
-{
- struct mailbox_vfuncs *v = box->vlast;
- struct stats_mailbox *sbox;
- struct stats_user *suser = STATS_USER_CONTEXT(box->storage->user);
-
- if (suser == NULL)
- return;
-
- stats_register_notify_callbacks(box->storage);
-
- sbox = p_new(box->pool, struct stats_mailbox, 1);
- sbox->module_ctx.super = *v;
- box->vlast = &sbox->module_ctx.super;
-
- v->transaction_begin = stats_transaction_begin;
- v->transaction_commit = stats_transaction_commit;
- v->transaction_rollback = stats_transaction_rollback;
- v->search_next_nonblock = stats_search_next_nonblock;
- MODULE_CONTEXT_SET(box, stats_storage_module, sbox);
-}
-
-static void session_stats_refresh_timeout(struct mail_user *user)
-{
- if (stats_global_user != NULL)
- stats_add_session(user);
- session_stats_refresh(user);
-}
-
-static void stats_io_deactivate(struct mail_user *user)
-{
- struct stats_user *suser = STATS_USER_CONTEXT_REQUIRE(user);
- unsigned int last_update_secs;
-
- if (stats_global_user == NULL)
- stats_add_session(user);
-
- last_update_secs = time(NULL) - suser->last_session_update;
- if (last_update_secs >= suser->refresh_secs) {
- if (stats_global_user != NULL)
- stats_add_session(user);
- session_stats_refresh(user);
- } else if (suser->to_stats_timeout == NULL) {
- suser->to_stats_timeout =
- timeout_add(suser->refresh_secs*1000,
- session_stats_refresh_timeout, user);
- }
-}
-
-static void stats_user_stats_fill(struct mail_user *user, struct stats *stats)
-{
- struct stats_user *suser = STATS_USER_CONTEXT_REQUIRE(user);
- struct mail_stats *mail_stats;
-
- mail_stats = stats_fill_ptr(stats, mail_stats_item);
- mail_stats_fill(suser, mail_stats);
-
- suser->module_ctx.super.stats_fill(user, stats);
-}
-
-static void stats_user_deinit(struct mail_user *user)
-{
- struct stats_user *suser = STATS_USER_CONTEXT_REQUIRE(user);
- struct stats_connection *stats_conn = suser->stats_conn;
-
- i_assert(stats_user_count > 0);
-
- stats_user_count--;
- if (stats_global_user != NULL) {
- /* we were updating the session lazily. do one final update. */
- i_assert(stats_global_user == user);
- stats_add_session(user);
- stats_global_user = NULL;
- }
-
- io_loop_context_remove_callbacks(suser->ioloop_ctx,
- stats_io_activate,
- stats_io_deactivate, user);
- /* send final stats before disconnection */
- session_stats_refresh(user);
- if (suser->stats_connected)
- mail_stats_connection_disconnect(stats_conn, user);
-
- timeout_remove(&suser->to_stats_timeout);
- suser->module_ctx.super.deinit(user);
-
- stats_connection_unref(&stats_conn);
-}
-
-static void stats_user_created(struct mail_user *user)
-{
- struct ioloop_context *ioloop_ctx =
- io_loop_get_current_context(current_ioloop);
- struct stats_user *suser;
- struct mail_user_vfuncs *v = user->vlast;
- const char *path, *str, *error;
- unsigned int refresh_secs;
-
- if (ioloop_ctx == NULL) {
- /* we're probably running some test program, or at least
- mail-storage-service wasn't used to create this user.
- disable stats tracking. */
- return;
- }
- if (user->autocreated) {
- /* lda / shared user. we're not tracking this one. */
- return;
- }
-
- /* get refresh time */
- str = mail_user_plugin_getenv(user, "old_stats_refresh");
- if (str == NULL)
- return;
- if (settings_get_time(str, &refresh_secs, &error) < 0) {
- i_error("stats: Invalid old_stats_refresh setting: %s", error);
- return;
- }
- if (refresh_secs == 0)
- return;
- if (refresh_secs > SESSION_STATS_FORCE_REFRESH_SECS) {
- i_warning("stats: stats_refresh too large, changing to %u",
- SESSION_STATS_FORCE_REFRESH_SECS);
- refresh_secs = SESSION_STATS_FORCE_REFRESH_SECS;
- }
-
- if (global_stats_conn == NULL) {
- path = mail_user_plugin_getenv(user, "old_stats_notify_path");
- if (path == NULL)
- path = MAIL_STATS_FIFO_NAME;
- if (path[0] != '/')
- path = t_strconcat(user->set->base_dir, "/", path, NULL);
- global_stats_conn = stats_connection_create(path);
- }
- stats_connection_ref(global_stats_conn);
-
- if (stats_user_count == 0) {
- /* first user connection */
- stats_global_user = user;
- } else if (stats_user_count == 1) {
- /* second user connection. we'll need to start doing
- per-io callback tracking now. (we might have been doing it
- also previously but just temporarily quickly dropped to
- having 1 user, in which case stats_global_user=NULL) */
- if (stats_global_user != NULL) {
- stats_add_session(stats_global_user);
- stats_global_user = NULL;
- }
- }
- stats_user_count++;
-
- suser = p_new(user->pool, struct stats_user, 1);
- suser->module_ctx.super = *v;
- user->vlast = &suser->module_ctx.super;
- v->deinit = stats_user_deinit;
- v->stats_fill = stats_user_stats_fill;
-
- suser->refresh_secs = refresh_secs;
- if (mail_user_plugin_getenv_bool(user, "old_stats_track_cmds"))
- suser->track_commands = TRUE;
-
- suser->stats_conn = global_stats_conn;
- if (user->session_id != NULL && user->session_id[0] != '\0')
- suser->stats_session_id = user->session_id;
- else {
- guid_128_t guid;
-
- guid_128_generate(guid);
- suser->stats_session_id =
- p_strdup(user->pool, guid_128_to_string(guid));
- }
- suser->last_session_update = time(NULL);
- user->stats_enabled = TRUE;
-
- suser->ioloop_ctx = ioloop_ctx;
- io_loop_context_add_callbacks(ioloop_ctx,
- stats_io_activate,
- stats_io_deactivate, user);
-
- suser->pre_io_stats = stats_alloc(user->pool);
- suser->session_stats = stats_alloc(user->pool);
- suser->last_sent_session_stats = stats_alloc(user->pool);
-
- MODULE_CONTEXT_SET(user, stats_user_module, suser);
- if (mail_stats_connection_connect(suser->stats_conn, user) == 0)
- suser->stats_connected = TRUE;
- suser->to_stats_timeout =
- timeout_add(suser->refresh_secs*1000,
- session_stats_refresh_timeout, user);
- /* fill the initial values. this is necessary for the process-global
- values (e.g. getrusage()) if the process is reused for multiple
- users. otherwise the next user will start with the previous one's
- last values. */
- mail_user_stats_fill(user, suser->pre_io_stats);
-}
-
-static struct mail_storage_hooks stats_mail_storage_hooks = {
- .mailbox_allocated = stats_mailbox_allocated,
- .mail_user_created = stats_user_created
-};
-
-void old_stats_plugin_init(struct module *module)
-{
- mail_stats_item = stats_register(&mail_stats_vfuncs);
- mail_storage_hooks_add(module, &stats_mail_storage_hooks);
-}
-
-void old_stats_plugin_preinit(void)
-{
- mail_stats_global_preinit();
-}
-
-void old_stats_plugin_deinit(void)
-{
- if (global_stats_conn != NULL)
- stats_connection_unref(&global_stats_conn);
- mail_stats_fill_global_deinit();
- mail_storage_hooks_remove(&stats_mail_storage_hooks);
- stats_unregister(&mail_stats_item);
-}
+++ /dev/null
-#ifndef STATS_PLUGIN_H
-#define STATS_PLUGIN_H
-
-#include "module-context.h"
-#include "mail-user.h"
-#include "mail-storage-private.h"
-
-#define STATS_USER_CONTEXT(obj) \
- MODULE_CONTEXT(obj, stats_user_module)
-
-#define STATS_USER_CONTEXT_REQUIRE(obj) \
- MODULE_CONTEXT_REQUIRE(obj, stats_user_module)
-
-struct stats_user {
- union mail_user_module_context module_ctx;
-
- struct ioloop_context *ioloop_ctx;
- struct stats_connection *stats_conn;
- const char *stats_session_id;
- bool stats_connected;
-
- unsigned int refresh_secs;
- bool track_commands;
- unsigned int refresh_check_counter;
-
- /* current session statistics */
- struct stats *session_stats;
- /* cumulative trans_stats for all already freed transactions. */
- struct mailbox_transaction_stats finished_transaction_stats;
- /* stats before calling IO callback. after IO callback this value is
- compared to current stats to see the difference */
- struct stats *pre_io_stats;
-
- time_t last_session_update;
- struct timeout *to_stats_timeout;
- /* stats that were last sent to stats server */
- struct stats *last_sent_session_stats;
- bool session_sent_duplicate;
-
- /* list of all currently existing transactions for this user */
- struct stats_transaction_context *transactions;
-};
-
-struct stats_transaction_context {
- union mailbox_transaction_module_context module_ctx;
-
- struct stats_transaction_context *prev, *next;
- struct mailbox_transaction_context *trans;
-
- struct mailbox_transaction_stats prev_stats;
-};
-
-extern MODULE_CONTEXT_DEFINE(stats_user_module, &mail_user_module_register);
-extern MODULE_CONTEXT_DEFINE(stats_storage_module, &mail_storage_module_register);
-
-void old_stats_plugin_init(struct module *module);
-void old_stats_plugin_preinit(void);
-void old_stats_plugin_deinit(void);
-
-#endif