summaryrefslogtreecommitdiffstats
path: root/src/old-stats/client.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/old-stats/client.c')
-rw-r--r--src/old-stats/client.c193
1 files changed, 193 insertions, 0 deletions
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);
+ }
+}