diff options
Diffstat (limited to 'src/old-stats')
29 files changed, 3733 insertions, 0 deletions
diff --git a/src/old-stats/Makefile.am b/src/old-stats/Makefile.am new file mode 100644 index 0000000..8cb9c2f --- /dev/null +++ b/src/old-stats/Makefile.am @@ -0,0 +1,48 @@ +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 diff --git a/src/old-stats/Makefile.in b/src/old-stats/Makefile.in new file mode 100644 index 0000000..0946bf2 --- /dev/null +++ b/src/old-stats/Makefile.in @@ -0,0 +1,882 @@ +# Makefile.in generated by automake 1.16.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2018 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + +VPATH = @srcdir@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +pkglibexec_PROGRAMS = old-stats$(EXEEXT) +subdir = src/old-stats +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/ac_checktype2.m4 \ + $(top_srcdir)/m4/ac_typeof.m4 $(top_srcdir)/m4/arc4random.m4 \ + $(top_srcdir)/m4/blockdev.m4 $(top_srcdir)/m4/c99_vsnprintf.m4 \ + $(top_srcdir)/m4/clock_gettime.m4 $(top_srcdir)/m4/crypt.m4 \ + $(top_srcdir)/m4/crypt_xpg6.m4 $(top_srcdir)/m4/dbqlk.m4 \ + $(top_srcdir)/m4/dirent_dtype.m4 $(top_srcdir)/m4/dovecot.m4 \ + $(top_srcdir)/m4/fd_passing.m4 $(top_srcdir)/m4/fdatasync.m4 \ + $(top_srcdir)/m4/flexible_array_member.m4 \ + $(top_srcdir)/m4/glibc.m4 $(top_srcdir)/m4/gmtime_max.m4 \ + $(top_srcdir)/m4/gmtime_tm_gmtoff.m4 \ + $(top_srcdir)/m4/ioloop.m4 $(top_srcdir)/m4/iovec.m4 \ + $(top_srcdir)/m4/ipv6.m4 $(top_srcdir)/m4/libcap.m4 \ + $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/libwrap.m4 \ + $(top_srcdir)/m4/linux_mremap.m4 $(top_srcdir)/m4/ltoptions.m4 \ + $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ + $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/mmap_write.m4 \ + $(top_srcdir)/m4/mntctl.m4 $(top_srcdir)/m4/modules.m4 \ + $(top_srcdir)/m4/notify.m4 $(top_srcdir)/m4/nsl.m4 \ + $(top_srcdir)/m4/off_t_max.m4 $(top_srcdir)/m4/pkg.m4 \ + $(top_srcdir)/m4/pr_set_dumpable.m4 \ + $(top_srcdir)/m4/q_quotactl.m4 $(top_srcdir)/m4/quota.m4 \ + $(top_srcdir)/m4/random.m4 $(top_srcdir)/m4/rlimit.m4 \ + $(top_srcdir)/m4/sendfile.m4 $(top_srcdir)/m4/size_t_signed.m4 \ + $(top_srcdir)/m4/sockpeercred.m4 $(top_srcdir)/m4/sql.m4 \ + $(top_srcdir)/m4/ssl.m4 $(top_srcdir)/m4/st_tim.m4 \ + $(top_srcdir)/m4/static_array.m4 $(top_srcdir)/m4/test_with.m4 \ + $(top_srcdir)/m4/time_t.m4 $(top_srcdir)/m4/typeof.m4 \ + $(top_srcdir)/m4/typeof_dev_t.m4 \ + $(top_srcdir)/m4/uoff_t_max.m4 $(top_srcdir)/m4/vararg.m4 \ + $(top_srcdir)/m4/want_apparmor.m4 \ + $(top_srcdir)/m4/want_bsdauth.m4 \ + $(top_srcdir)/m4/want_bzlib.m4 \ + $(top_srcdir)/m4/want_cassandra.m4 \ + $(top_srcdir)/m4/want_cdb.m4 \ + $(top_srcdir)/m4/want_checkpassword.m4 \ + $(top_srcdir)/m4/want_clucene.m4 $(top_srcdir)/m4/want_db.m4 \ + $(top_srcdir)/m4/want_gssapi.m4 $(top_srcdir)/m4/want_icu.m4 \ + $(top_srcdir)/m4/want_ldap.m4 $(top_srcdir)/m4/want_lua.m4 \ + $(top_srcdir)/m4/want_lz4.m4 $(top_srcdir)/m4/want_lzma.m4 \ + $(top_srcdir)/m4/want_mysql.m4 $(top_srcdir)/m4/want_pam.m4 \ + $(top_srcdir)/m4/want_passwd.m4 $(top_srcdir)/m4/want_pgsql.m4 \ + $(top_srcdir)/m4/want_prefetch.m4 \ + $(top_srcdir)/m4/want_shadow.m4 \ + $(top_srcdir)/m4/want_sodium.m4 $(top_srcdir)/m4/want_solr.m4 \ + $(top_srcdir)/m4/want_sqlite.m4 \ + $(top_srcdir)/m4/want_stemmer.m4 \ + $(top_srcdir)/m4/want_systemd.m4 \ + $(top_srcdir)/m4/want_textcat.m4 \ + $(top_srcdir)/m4/want_unwind.m4 $(top_srcdir)/m4/want_zlib.m4 \ + $(top_srcdir)/m4/want_zstd.m4 $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(noinst_HEADERS) \ + $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +am__installdirs = "$(DESTDIR)$(pkglibexecdir)" +PROGRAMS = $(pkglibexec_PROGRAMS) +am_old_stats_OBJECTS = client.$(OBJEXT) client-export.$(OBJEXT) \ + client-reset.$(OBJEXT) fifo-input-connection.$(OBJEXT) \ + global-memory.$(OBJEXT) mail-command.$(OBJEXT) \ + mail-domain.$(OBJEXT) mail-ip.$(OBJEXT) mail-session.$(OBJEXT) \ + mail-stats.$(OBJEXT) mail-user.$(OBJEXT) main.$(OBJEXT) \ + stats-carbon.$(OBJEXT) stats-settings.$(OBJEXT) +old_stats_OBJECTS = $(am_old_stats_OBJECTS) +am__DEPENDENCIES_1 = +AM_V_lt = $(am__v_lt_@AM_V@) +am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) +am__v_lt_0 = --silent +am__v_lt_1 = +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__maybe_remake_depfiles = depfiles +am__depfiles_remade = ./$(DEPDIR)/client-export.Po \ + ./$(DEPDIR)/client-reset.Po ./$(DEPDIR)/client.Po \ + ./$(DEPDIR)/fifo-input-connection.Po \ + ./$(DEPDIR)/global-memory.Po ./$(DEPDIR)/mail-command.Po \ + ./$(DEPDIR)/mail-domain.Po ./$(DEPDIR)/mail-ip.Po \ + ./$(DEPDIR)/mail-session.Po ./$(DEPDIR)/mail-stats.Po \ + ./$(DEPDIR)/mail-user.Po ./$(DEPDIR)/main.Po \ + ./$(DEPDIR)/stats-carbon.Po ./$(DEPDIR)/stats-settings.Po +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_@AM_V@) +am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) +am__v_CC_0 = @echo " CC " $@; +am__v_CC_1 = +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_@AM_V@) +am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) +am__v_CCLD_0 = @echo " CCLD " $@; +am__v_CCLD_1 = +SOURCES = $(old_stats_SOURCES) +DIST_SOURCES = $(old_stats_SOURCES) +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +HEADERS = $(noinst_HEADERS) +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +ETAGS = etags +CTAGS = ctags +am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +pkglibexecdir = $(libexecdir)/dovecot +ACLOCAL = @ACLOCAL@ +ACLOCAL_AMFLAGS = @ACLOCAL_AMFLAGS@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +APPARMOR_LIBS = @APPARMOR_LIBS@ +AR = @AR@ +AUTH_CFLAGS = @AUTH_CFLAGS@ +AUTH_LIBS = @AUTH_LIBS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BINARY_CFLAGS = @BINARY_CFLAGS@ +BINARY_LDFLAGS = @BINARY_LDFLAGS@ +BISON = @BISON@ +CASSANDRA_CFLAGS = @CASSANDRA_CFLAGS@ +CASSANDRA_LIBS = @CASSANDRA_LIBS@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CDB_LIBS = @CDB_LIBS@ +CFLAGS = @CFLAGS@ +CLUCENE_CFLAGS = @CLUCENE_CFLAGS@ +CLUCENE_LIBS = @CLUCENE_LIBS@ +COMPRESS_LIBS = @COMPRESS_LIBS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CRYPT_LIBS = @CRYPT_LIBS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DICT_LIBS = @DICT_LIBS@ +DLLIB = @DLLIB@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +FLEX = @FLEX@ +FUZZER_CPPFLAGS = @FUZZER_CPPFLAGS@ +FUZZER_LDFLAGS = @FUZZER_LDFLAGS@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +KRB5CONFIG = @KRB5CONFIG@ +KRB5_CFLAGS = @KRB5_CFLAGS@ +KRB5_LIBS = @KRB5_LIBS@ +LD = @LD@ +LDAP_LIBS = @LDAP_LIBS@ +LDFLAGS = @LDFLAGS@ +LD_NO_WHOLE_ARCHIVE = @LD_NO_WHOLE_ARCHIVE@ +LD_WHOLE_ARCHIVE = @LD_WHOLE_ARCHIVE@ +LIBCAP = @LIBCAP@ +LIBDOVECOT = @LIBDOVECOT@ +LIBDOVECOT_COMPRESS = @LIBDOVECOT_COMPRESS@ +LIBDOVECOT_DEPS = @LIBDOVECOT_DEPS@ +LIBDOVECOT_DSYNC = @LIBDOVECOT_DSYNC@ +LIBDOVECOT_LA_LIBS = @LIBDOVECOT_LA_LIBS@ +LIBDOVECOT_LDA = @LIBDOVECOT_LDA@ +LIBDOVECOT_LDAP = @LIBDOVECOT_LDAP@ +LIBDOVECOT_LIBFTS = @LIBDOVECOT_LIBFTS@ +LIBDOVECOT_LIBFTS_DEPS = @LIBDOVECOT_LIBFTS_DEPS@ +LIBDOVECOT_LOGIN = @LIBDOVECOT_LOGIN@ +LIBDOVECOT_LUA = @LIBDOVECOT_LUA@ +LIBDOVECOT_LUA_DEPS = @LIBDOVECOT_LUA_DEPS@ +LIBDOVECOT_SQL = @LIBDOVECOT_SQL@ +LIBDOVECOT_STORAGE = @LIBDOVECOT_STORAGE@ +LIBDOVECOT_STORAGE_DEPS = @LIBDOVECOT_STORAGE_DEPS@ +LIBEXTTEXTCAT_CFLAGS = @LIBEXTTEXTCAT_CFLAGS@ +LIBEXTTEXTCAT_LIBS = @LIBEXTTEXTCAT_LIBS@ +LIBICONV = @LIBICONV@ +LIBICU_CFLAGS = @LIBICU_CFLAGS@ +LIBICU_LIBS = @LIBICU_LIBS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBSODIUM_CFLAGS = @LIBSODIUM_CFLAGS@ +LIBSODIUM_LIBS = @LIBSODIUM_LIBS@ +LIBTIRPC_CFLAGS = @LIBTIRPC_CFLAGS@ +LIBTIRPC_LIBS = @LIBTIRPC_LIBS@ +LIBTOOL = @LIBTOOL@ +LIBUNWIND_CFLAGS = @LIBUNWIND_CFLAGS@ +LIBUNWIND_LIBS = @LIBUNWIND_LIBS@ +LIBWRAP_LIBS = @LIBWRAP_LIBS@ +LINKED_STORAGE_LDADD = @LINKED_STORAGE_LDADD@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBICONV = @LTLIBICONV@ +LTLIBOBJS = @LTLIBOBJS@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +LUA_CFLAGS = @LUA_CFLAGS@ +LUA_LIBS = @LUA_LIBS@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MKDIR_P = @MKDIR_P@ +MODULE_LIBS = @MODULE_LIBS@ +MODULE_SUFFIX = @MODULE_SUFFIX@ +MYSQL_CFLAGS = @MYSQL_CFLAGS@ +MYSQL_CONFIG = @MYSQL_CONFIG@ +MYSQL_LIBS = @MYSQL_LIBS@ +NM = @NM@ +NMEDIT = @NMEDIT@ +NOPLUGIN_LDFLAGS = @NOPLUGIN_LDFLAGS@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PANDOC = @PANDOC@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PGSQL_CFLAGS = @PGSQL_CFLAGS@ +PGSQL_LIBS = @PGSQL_LIBS@ +PG_CONFIG = @PG_CONFIG@ +PIE_CFLAGS = @PIE_CFLAGS@ +PIE_LDFLAGS = @PIE_LDFLAGS@ +PKG_CONFIG = @PKG_CONFIG@ +PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ +PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ +QUOTA_LIBS = @QUOTA_LIBS@ +RANLIB = @RANLIB@ +RELRO_LDFLAGS = @RELRO_LDFLAGS@ +RPCGEN = @RPCGEN@ +RUN_TEST = @RUN_TEST@ +SED = @SED@ +SETTING_FILES = @SETTING_FILES@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SQLITE_CFLAGS = @SQLITE_CFLAGS@ +SQLITE_LIBS = @SQLITE_LIBS@ +SQL_CFLAGS = @SQL_CFLAGS@ +SQL_LIBS = @SQL_LIBS@ +SSL_CFLAGS = @SSL_CFLAGS@ +SSL_LIBS = @SSL_LIBS@ +STRIP = @STRIP@ +SYSTEMD_CFLAGS = @SYSTEMD_CFLAGS@ +SYSTEMD_LIBS = @SYSTEMD_LIBS@ +VALGRIND = @VALGRIND@ +VERSION = @VERSION@ +ZSTD_CFLAGS = @ZSTD_CFLAGS@ +ZSTD_LIBS = @ZSTD_LIBS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +dict_drivers = @dict_drivers@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +moduledir = @moduledir@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +rundir = @rundir@ +runstatedir = @runstatedir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sql_drivers = @sql_drivers@ +srcdir = @srcdir@ +ssldir = @ssldir@ +statedir = @statedir@ +sysconfdir = @sysconfdir@ +systemdservicetype = @systemdservicetype@ +systemdsystemunitdir = @systemdsystemunitdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +old_stats_moduledir = $(moduledir)/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 + +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/old-stats/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign src/old-stats/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): +install-pkglibexecPROGRAMS: $(pkglibexec_PROGRAMS) + @$(NORMAL_INSTALL) + @list='$(pkglibexec_PROGRAMS)'; test -n "$(pkglibexecdir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(pkglibexecdir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(pkglibexecdir)" || exit 1; \ + fi; \ + for p in $$list; do echo "$$p $$p"; done | \ + sed 's/$(EXEEXT)$$//' | \ + while read p p1; do if test -f $$p \ + || test -f $$p1 \ + ; then echo "$$p"; echo "$$p"; else :; fi; \ + done | \ + sed -e 'p;s,.*/,,;n;h' \ + -e 's|.*|.|' \ + -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ + sed 'N;N;N;s,\n, ,g' | \ + $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ + { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ + if ($$2 == $$4) files[d] = files[d] " " $$1; \ + else { print "f", $$3 "/" $$4, $$1; } } \ + END { for (d in files) print "f", d, files[d] }' | \ + while read type dir files; do \ + if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ + test -z "$$files" || { \ + echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(pkglibexecdir)$$dir'"; \ + $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(pkglibexecdir)$$dir" || exit $$?; \ + } \ + ; done + +uninstall-pkglibexecPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(pkglibexec_PROGRAMS)'; test -n "$(pkglibexecdir)" || list=; \ + files=`for p in $$list; do echo "$$p"; done | \ + sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ + -e 's/$$/$(EXEEXT)/' \ + `; \ + test -n "$$list" || exit 0; \ + echo " ( cd '$(DESTDIR)$(pkglibexecdir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(pkglibexecdir)" && rm -f $$files + +clean-pkglibexecPROGRAMS: + @list='$(pkglibexec_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list + +old-stats$(EXEEXT): $(old_stats_OBJECTS) $(old_stats_DEPENDENCIES) $(EXTRA_old_stats_DEPENDENCIES) + @rm -f old-stats$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(old_stats_OBJECTS) $(old_stats_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/client-export.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/client-reset.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/client.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fifo-input-connection.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/global-memory.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mail-command.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mail-domain.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mail-ip.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mail-session.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mail-stats.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mail-user.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/main.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stats-carbon.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stats-settings.Po@am__quote@ # am--include-marker + +$(am__depfiles_remade): + @$(MKDIR_P) $(@D) + @echo '# dummy' >$@-t && $(am__mv) $@-t $@ + +am--depfiles: $(am__depfiles_remade) + +.c.o: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< + +.c.obj: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-am +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + $(am__define_uniq_tagged_files); \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: ctags-am + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" +cscopelist: cscopelist-am + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) distdir-am + +distdir-am: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(PROGRAMS) $(HEADERS) +installdirs: + for dir in "$(DESTDIR)$(pkglibexecdir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool clean-pkglibexecPROGRAMS \ + mostlyclean-am + +distclean: distclean-am + -rm -f ./$(DEPDIR)/client-export.Po + -rm -f ./$(DEPDIR)/client-reset.Po + -rm -f ./$(DEPDIR)/client.Po + -rm -f ./$(DEPDIR)/fifo-input-connection.Po + -rm -f ./$(DEPDIR)/global-memory.Po + -rm -f ./$(DEPDIR)/mail-command.Po + -rm -f ./$(DEPDIR)/mail-domain.Po + -rm -f ./$(DEPDIR)/mail-ip.Po + -rm -f ./$(DEPDIR)/mail-session.Po + -rm -f ./$(DEPDIR)/mail-stats.Po + -rm -f ./$(DEPDIR)/mail-user.Po + -rm -f ./$(DEPDIR)/main.Po + -rm -f ./$(DEPDIR)/stats-carbon.Po + -rm -f ./$(DEPDIR)/stats-settings.Po + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: install-pkglibexecPROGRAMS + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f ./$(DEPDIR)/client-export.Po + -rm -f ./$(DEPDIR)/client-reset.Po + -rm -f ./$(DEPDIR)/client.Po + -rm -f ./$(DEPDIR)/fifo-input-connection.Po + -rm -f ./$(DEPDIR)/global-memory.Po + -rm -f ./$(DEPDIR)/mail-command.Po + -rm -f ./$(DEPDIR)/mail-domain.Po + -rm -f ./$(DEPDIR)/mail-ip.Po + -rm -f ./$(DEPDIR)/mail-session.Po + -rm -f ./$(DEPDIR)/mail-stats.Po + -rm -f ./$(DEPDIR)/mail-user.Po + -rm -f ./$(DEPDIR)/main.Po + -rm -f ./$(DEPDIR)/stats-carbon.Po + -rm -f ./$(DEPDIR)/stats-settings.Po + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-pkglibexecPROGRAMS + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \ + clean-generic clean-libtool clean-pkglibexecPROGRAMS \ + cscopelist-am ctags ctags-am distclean distclean-compile \ + distclean-generic distclean-libtool distclean-tags distdir dvi \ + dvi-am html html-am info info-am install install-am \ + install-data install-data-am install-dvi install-dvi-am \ + install-exec install-exec-am install-html install-html-am \ + install-info install-info-am install-man install-pdf \ + install-pdf-am install-pkglibexecPROGRAMS install-ps \ + install-ps-am install-strip installcheck installcheck-am \ + installdirs maintainer-clean maintainer-clean-generic \ + mostlyclean mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \ + uninstall-am uninstall-pkglibexecPROGRAMS + +.PRECIOUS: Makefile + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/old-stats/client-export.c b/src/old-stats/client-export.c new file mode 100644 index 0000000..e020d13 --- /dev/null +++ b/src/old-stats/client-export.c @@ -0,0 +1,657 @@ +/* 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%ld", (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); +} diff --git a/src/old-stats/client-export.h b/src/old-stats/client-export.h new file mode 100644 index 0000000..ddca138 --- /dev/null +++ b/src/old-stats/client-export.h @@ -0,0 +1,9 @@ +#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 diff --git a/src/old-stats/client-reset.c b/src/old-stats/client-reset.c new file mode 100644 index 0000000..965bb22 --- /dev/null +++ b/src/old-stats/client-reset.c @@ -0,0 +1,21 @@ +/* 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; +} diff --git a/src/old-stats/client-reset.h b/src/old-stats/client-reset.h new file mode 100644 index 0000000..7a84d61 --- /dev/null +++ b/src/old-stats/client-reset.h @@ -0,0 +1,9 @@ +#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 diff --git a/src/old-stats/client.c b/src/old-stats/client.c new file mode 100644 index 0000000..5a6d5cb --- /dev/null +++ b/src/old-stats/client.c @@ -0,0 +1,193 @@ +/* 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); + } +} diff --git a/src/old-stats/client.h b/src/old-stats/client.h new file mode 100644 index 0000000..5650d7f --- /dev/null +++ b/src/old-stats/client.h @@ -0,0 +1,35 @@ +#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 diff --git a/src/old-stats/fifo-input-connection.c b/src/old-stats/fifo-input-connection.c new file mode 100644 index 0000000..1b9759d --- /dev/null +++ b/src/old-stats/fifo-input-connection.c @@ -0,0 +1,108 @@ +/* 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); + } +} diff --git a/src/old-stats/fifo-input-connection.h b/src/old-stats/fifo-input-connection.h new file mode 100644 index 0000000..ff394a5 --- /dev/null +++ b/src/old-stats/fifo-input-connection.h @@ -0,0 +1,9 @@ +#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 diff --git a/src/old-stats/global-memory.c b/src/old-stats/global-memory.c new file mode 100644 index 0000000..dc04bfb --- /dev/null +++ b/src/old-stats/global-memory.c @@ -0,0 +1,46 @@ +/* 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; +} diff --git a/src/old-stats/global-memory.h b/src/old-stats/global-memory.h new file mode 100644 index 0000000..840ffc7 --- /dev/null +++ b/src/old-stats/global-memory.h @@ -0,0 +1,9 @@ +#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 diff --git a/src/old-stats/mail-command.c b/src/old-stats/mail-command.c new file mode 100644 index 0000000..98fdc9d --- /dev/null +++ b/src/old-stats/mail-command.c @@ -0,0 +1,247 @@ +/* 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); + } +} diff --git a/src/old-stats/mail-command.h b/src/old-stats/mail-command.h new file mode 100644 index 0000000..681af83 --- /dev/null +++ b/src/old-stats/mail-command.h @@ -0,0 +1,18 @@ +#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 diff --git a/src/old-stats/mail-domain.c b/src/old-stats/mail-domain.c new file mode 100644 index 0000000..140fc15 --- /dev/null +++ b/src/old-stats/mail-domain.c @@ -0,0 +1,133 @@ +/* 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); +} diff --git a/src/old-stats/mail-domain.h b/src/old-stats/mail-domain.h new file mode 100644 index 0000000..23e2fbe --- /dev/null +++ b/src/old-stats/mail-domain.h @@ -0,0 +1,22 @@ +#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 diff --git a/src/old-stats/mail-ip.c b/src/old-stats/mail-ip.c new file mode 100644 index 0000000..bb0209f --- /dev/null +++ b/src/old-stats/mail-ip.c @@ -0,0 +1,129 @@ +/* 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); +} diff --git a/src/old-stats/mail-ip.h b/src/old-stats/mail-ip.h new file mode 100644 index 0000000..f7ff864 --- /dev/null +++ b/src/old-stats/mail-ip.h @@ -0,0 +1,19 @@ +#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 diff --git a/src/old-stats/mail-session.c b/src/old-stats/mail-session.c new file mode 100644 index 0000000..db202b3 --- /dev/null +++ b/src/old-stats/mail-session.c @@ -0,0 +1,343 @@ +/* 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); +} diff --git a/src/old-stats/mail-session.h b/src/old-stats/mail-session.h new file mode 100644 index 0000000..efdc82a --- /dev/null +++ b/src/old-stats/mail-session.h @@ -0,0 +1,28 @@ +#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 diff --git a/src/old-stats/mail-stats.c b/src/old-stats/mail-stats.c new file mode 100644 index 0000000..6ba3250 --- /dev/null +++ b/src/old-stats/mail-stats.c @@ -0,0 +1,86 @@ +/* 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; +} diff --git a/src/old-stats/mail-stats.h b/src/old-stats/mail-stats.h new file mode 100644 index 0000000..efd0824 --- /dev/null +++ b/src/old-stats/mail-stats.h @@ -0,0 +1,123 @@ +#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 diff --git a/src/old-stats/mail-user.c b/src/old-stats/mail-user.c new file mode 100644 index 0000000..7b3bc7a --- /dev/null +++ b/src/old-stats/mail-user.c @@ -0,0 +1,177 @@ +/* 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); +} diff --git a/src/old-stats/mail-user.h b/src/old-stats/mail-user.h new file mode 100644 index 0000000..ff1949e --- /dev/null +++ b/src/old-stats/mail-user.h @@ -0,0 +1,23 @@ +#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 diff --git a/src/old-stats/main.c b/src/old-stats/main.c new file mode 100644 index 0000000..49f50f4 --- /dev/null +++ b/src/old-stats/main.c @@ -0,0 +1,95 @@ +/* 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; +} diff --git a/src/old-stats/stats-carbon.c b/src/old-stats/stats-carbon.c new file mode 100644 index 0000000..7e984cf --- /dev/null +++ b/src/old-stats/stats-carbon.c @@ -0,0 +1,125 @@ +/* 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); + if (net_ipport2str(&ip, port, &host) < 0) + i_unreached(); + ctx->endpoint = p_strdup(ctx->pool, host); + ctx->callback = callback; + ctx->ctx = cb_ctx; + + *ctx_r = ctx; + + return 0; +} diff --git a/src/old-stats/stats-carbon.h b/src/old-stats/stats-carbon.h new file mode 100644 index 0000000..0785976 --- /dev/null +++ b/src/old-stats/stats-carbon.h @@ -0,0 +1,13 @@ +#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 diff --git a/src/old-stats/stats-settings.c b/src/old-stats/stats-settings.c new file mode 100644 index 0000000..3aa65af --- /dev/null +++ b/src/old-stats/stats-settings.c @@ -0,0 +1,104 @@ +/* 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; diff --git a/src/old-stats/stats-settings.h b/src/old-stats/stats-settings.h new file mode 100644 index 0000000..6b50b64 --- /dev/null +++ b/src/old-stats/stats-settings.h @@ -0,0 +1,22 @@ +#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 + |