connection.c revision a238c6fede2022e5a4af707107ffb8f047b7753f
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync/* Copyright (c) 2013-2016 Dovecot authors, see the included COPYING file */
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync#include "lib.h"
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync#include "ioloop.h"
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync#include "istream.h"
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync#include "ostream.h"
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync#include "iostream.h"
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync#include "net.h"
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync#include "strescape.h"
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync#include "llist.h"
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync#include "connection.h"
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync#include <unistd.h>
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsyncstatic void connection_idle_timeout(struct connection *conn)
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync{
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync conn->disconnect_reason = CONNECTION_DISCONNECT_IDLE_TIMEOUT;
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync conn->list->v.destroy(conn);
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync}
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsyncstatic void connection_connect_timeout(struct connection *conn)
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync{
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync conn->disconnect_reason = CONNECTION_DISCONNECT_CONNECT_TIMEOUT;
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync conn->list->v.destroy(conn);
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync}
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsyncvoid connection_input_default(struct connection *conn)
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync{
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync const char *line;
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync struct istream *input;
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync struct ostream *output;
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync int ret = 0;
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync switch (connection_input_read(conn)) {
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync case -1:
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync return;
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync case 0: /* allow calling this function for buffered input */
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync case 1:
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync break;
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync default:
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync i_unreached();
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync }
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync input = conn->input;
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync output = conn->output;
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync i_stream_ref(input);
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync if (output != NULL) {
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync o_stream_ref(output);
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync o_stream_cork(output);
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync }
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync while (!input->closed && (line = i_stream_next_line(input)) != NULL) {
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync T_BEGIN {
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync ret = conn->list->v.input_line(conn, line);
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync } T_END;
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync if (ret <= 0)
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync break;
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync }
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync if (output != NULL) {
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync o_stream_uncork(output);
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync o_stream_unref(&output);
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync }
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync if (ret < 0 && !input->closed) {
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync conn->disconnect_reason = CONNECTION_DISCONNECT_DEINIT;
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync conn->list->v.destroy(conn);
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync }
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync i_stream_unref(&input);
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync}
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsyncint connection_verify_version(struct connection *conn,
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync const char *const *args)
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync{
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync unsigned int recv_major_version;
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync /* VERSION <tab> service_name <tab> major version <tab> minor version */
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync if (str_array_length(args) != 4 ||
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync strcmp(args[0], "VERSION") != 0 ||
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync str_to_uint(args[2], &recv_major_version) < 0 ||
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync str_to_uint(args[3], &conn->minor_version) < 0) {
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync i_error("%s didn't reply with a valid VERSION line",
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync conn->name);
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync return -1;
a2728e9b5352fca07e2f765819a8bcc301722141vboxsync }
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync if (strcmp(args[1], conn->list->set.service_name_in) != 0) {
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync i_error("%s: Connected to wrong socket type. "
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync "We want '%s', but received '%s'", conn->name,
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync conn->list->set.service_name_in, args[1]);
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync return -1;
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync }
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync if (recv_major_version != conn->list->set.major_version) {
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync i_error("%s: Socket supports major version %u, "
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync "but we support only %u (mixed old and new binaries?)",
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync conn->name, recv_major_version,
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync conn->list->set.major_version);
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync return -1;
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync }
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync return 0;
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync}
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsyncint connection_input_line_default(struct connection *conn, const char *line)
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync{
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync const char *const *args;
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync args = t_strsplit_tabescaped(line);
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync if (!conn->version_received) {
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync if (connection_verify_version(conn, args) < 0)
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync return -1;
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync conn->version_received = TRUE;
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync return 1;
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync }
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync return conn->list->v.input_args(conn, args);
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync}
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsyncstatic void connection_init_streams(struct connection *conn)
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync{
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync const struct connection_settings *set = &conn->list->set;
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync i_assert(conn->io == NULL);
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync i_assert(conn->input == NULL);
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync i_assert(conn->output == NULL);
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync i_assert(conn->to == NULL);
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync conn->version_received = set->major_version == 0;
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync if (set->input_max_size != 0) {
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync conn->input = i_stream_create_fd(conn->fd_in,
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync set->input_max_size);
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync i_stream_set_name(conn->input, conn->name);
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync conn->io = io_add_istream(conn->input, *conn->list->v.input, conn);
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync } else {
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync conn->io = io_add(conn->fd_in, IO_READ, *conn->list->v.input, conn);
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync }
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync if (set->output_max_size != 0) {
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync conn->output = o_stream_create_fd(conn->fd_out,
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync set->output_max_size);
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync o_stream_set_no_error_handling(conn->output, TRUE);
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync o_stream_set_name(conn->output, conn->name);
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync }
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync if (set->input_idle_timeout_secs != 0) {
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync conn->to = timeout_add(set->input_idle_timeout_secs*1000,
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync connection_idle_timeout, conn);
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync }
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync if (set->major_version != 0 && !set->dont_send_version) {
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync o_stream_nsend_str(conn->output, t_strdup_printf(
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync "VERSION\t%s\t%u\t%u\n", set->service_name_out,
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync set->major_version, set->minor_version));
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync }
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync}
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsyncstatic void connection_client_connected(struct connection *conn, bool success)
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync{
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync i_assert(conn->list->set.client);
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync if (success)
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync connection_init_streams(conn);
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync if (conn->list->v.client_connected != NULL)
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync conn->list->v.client_connected(conn, success);
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync if (!success) {
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync conn->disconnect_reason =
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync CONNECTION_DISCONNECT_CONN_CLOSED;
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync conn->list->v.destroy(conn);
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync }
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync}
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsyncvoid connection_init_server(struct connection_list *list,
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync struct connection *conn, const char *name,
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync int fd_in, int fd_out)
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync{
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync i_assert(name != NULL);
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync i_assert(!list->set.client);
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync conn->list = list;
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync conn->name = i_strdup(name);
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync conn->fd_in = fd_in;
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync conn->fd_out = fd_out;
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync connection_init_streams(conn);
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync DLLIST_PREPEND(&list->connections, conn);
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync list->connections_count++;
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync}
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsyncvoid connection_init_client_ip(struct connection_list *list,
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync struct connection *conn,
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync const struct ip_addr *ip, in_port_t port)
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync{
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync i_assert(list->set.client);
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync conn->fd_in = conn->fd_out = -1;
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync conn->list = list;
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync conn->name = i_strdup_printf("%s:%u", net_ip2addr(ip), port);
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync conn->ip = *ip;
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync conn->port = port;
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync DLLIST_PREPEND(&list->connections, conn);
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync list->connections_count++;
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync}
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsyncvoid connection_init_client_unix(struct connection_list *list,
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync struct connection *conn, const char *path)
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync{
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync i_assert(list->set.client);
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync conn->fd_in = conn->fd_out = -1;
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync conn->list = list;
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync conn->name = i_strdup(path);
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync DLLIST_PREPEND(&list->connections, conn);
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync list->connections_count++;
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync}
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsyncvoid connection_init_from_streams(struct connection_list *list,
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync struct connection *conn, const char *name,
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync struct istream *input, struct ostream *output)
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync{
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync i_assert(name != NULL);
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync conn->list = list;
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync conn->name = i_strdup(name);
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync conn->fd_in = i_stream_get_fd(input);
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync conn->fd_out = o_stream_get_fd(output);
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync i_assert(conn->fd_in >= 0);
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync i_assert(conn->fd_out >= 0);
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync i_assert(conn->io == NULL);
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync i_assert(conn->input == NULL);
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync i_assert(conn->output == NULL);
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync i_assert(conn->to == NULL);
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync conn->input = input;
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync i_stream_ref(conn->input);
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync i_stream_set_name(conn->input, conn->name);
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync conn->output = output;
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync o_stream_ref(conn->output);
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync o_stream_set_no_error_handling(conn->output, TRUE);
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync o_stream_set_name(conn->output, conn->name);
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync conn->io = io_add_istream(conn->input, *list->v.input, conn);
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync DLLIST_PREPEND(&list->connections, conn);
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync list->connections_count++;
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync if (list->v.client_connected != NULL)
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync list->v.client_connected(conn, TRUE);
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync}
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsyncstatic void connection_socket_connected(struct connection *conn)
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync{
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync io_remove(&conn->io);
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync if (conn->to != NULL)
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync timeout_remove(&conn->to);
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync errno = net_geterror(conn->fd_in);
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync connection_client_connected(conn, errno == 0);
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync}
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsyncint connection_client_connect(struct connection *conn)
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync{
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync const struct connection_settings *set = &conn->list->set;
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync int fd;
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync i_assert(conn->list->set.client);
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync i_assert(conn->fd_in == -1);
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync if (conn->port != 0)
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync fd = net_connect_ip(&conn->ip, conn->port, NULL);
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync else if (conn->list->set.unix_client_connect_msecs == 0)
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync fd = net_connect_unix(conn->name);
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync else
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync fd = net_connect_unix_with_retries(conn->name, conn->list->set.unix_client_connect_msecs);
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync if (fd == -1)
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync return -1;
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync conn->fd_in = conn->fd_out = fd;
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync if (conn->port != 0 ||
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync conn->list->set.delayed_unix_client_connected_callback) {
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync conn->io = io_add(conn->fd_out, IO_WRITE,
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync connection_socket_connected, conn);
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync if (set->client_connect_timeout_msecs != 0) {
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync conn->to = timeout_add(set->client_connect_timeout_msecs,
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync connection_connect_timeout, conn);
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync }
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync } else {
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync connection_client_connected(conn, TRUE);
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync }
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync return 0;
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync}
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsyncvoid connection_disconnect(struct connection *conn)
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync{
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync conn->last_input = 0;
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync memset(&conn->last_input_tv, 0, sizeof(conn->last_input_tv));
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync if (conn->to != NULL)
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync timeout_remove(&conn->to);
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync if (conn->io != NULL)
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync io_remove(&conn->io);
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync if (conn->input != NULL) {
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync i_stream_close(conn->input);
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync i_stream_destroy(&conn->input);
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync }
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync if (conn->output != NULL) {
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync o_stream_close(conn->output);
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync o_stream_destroy(&conn->output);
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync }
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync if (conn->fd_in != -1) {
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync if (close(conn->fd_in) < 0)
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync i_error("close(%s) failed: %m", conn->name);
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync if (conn->fd_in != conn->fd_out && close(conn->fd_out) < 0)
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync i_error("close(%s/out) failed: %m", conn->name);
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync conn->fd_in = conn->fd_out = -1;
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync }
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync}
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsyncvoid connection_deinit(struct connection *conn)
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync{
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync i_assert(conn->list->connections_count > 0);
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync conn->list->connections_count--;
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync DLLIST_REMOVE(&conn->list->connections, conn);
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync connection_disconnect(conn);
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync i_free(conn->name);
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync}
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsyncint connection_input_read(struct connection *conn)
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync{
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync conn->last_input = ioloop_time;
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync conn->last_input_tv = ioloop_timeval;
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync if (conn->to != NULL)
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync timeout_reset(conn->to);
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync switch (i_stream_read(conn->input)) {
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync case -2:
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync /* buffer full */
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync switch (conn->list->set.input_full_behavior) {
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync case CONNECTION_BEHAVIOR_DESTROY:
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync conn->disconnect_reason =
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync CONNECTION_DISCONNECT_BUFFER_FULL;
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync conn->list->v.destroy(conn);
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync return -1;
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync case CONNECTION_BEHAVIOR_ALLOW:
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync return -2;
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync }
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync i_unreached();
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync case -1:
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync /* disconnected */
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync conn->disconnect_reason =
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync CONNECTION_DISCONNECT_CONN_CLOSED;
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync conn->list->v.destroy(conn);
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync return -1;
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync case 0:
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync /* nothing new read */
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync return 0;
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync default:
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync /* something was read */
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync return 1;
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync }
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync}
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsyncconst char *connection_disconnect_reason(struct connection *conn)
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync{
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync switch (conn->disconnect_reason) {
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync case CONNECTION_DISCONNECT_DEINIT:
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync return "Deinitializing";
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync case CONNECTION_DISCONNECT_CONNECT_TIMEOUT: {
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync unsigned int msecs =
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync conn->list->set.client_connect_timeout_msecs;
7c90a188b164765cebe27fa754d68a4321ded83evboxsync return t_strdup_printf("connect() timed out in %u.%03u secs",
7c90a188b164765cebe27fa754d68a4321ded83evboxsync msecs/1000, msecs%1000);
7c90a188b164765cebe27fa754d68a4321ded83evboxsync }
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync case CONNECTION_DISCONNECT_IDLE_TIMEOUT:
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync return "Idle timeout";
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync case CONNECTION_DISCONNECT_CONN_CLOSED:
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync if (conn->input == NULL)
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync return t_strdup_printf("connect() failed: %m");
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync /* fall through */
7c90a188b164765cebe27fa754d68a4321ded83evboxsync case CONNECTION_DISCONNECT_NOT:
7c90a188b164765cebe27fa754d68a4321ded83evboxsync case CONNECTION_DISCONNECT_BUFFER_FULL:
7c90a188b164765cebe27fa754d68a4321ded83evboxsync return io_stream_get_disconnect_reason(conn->input, conn->output);
7c90a188b164765cebe27fa754d68a4321ded83evboxsync }
7c90a188b164765cebe27fa754d68a4321ded83evboxsync i_unreached();
7c90a188b164765cebe27fa754d68a4321ded83evboxsync}
7c90a188b164765cebe27fa754d68a4321ded83evboxsync
7c90a188b164765cebe27fa754d68a4321ded83evboxsyncvoid connection_switch_ioloop(struct connection *conn)
7c90a188b164765cebe27fa754d68a4321ded83evboxsync{
7c90a188b164765cebe27fa754d68a4321ded83evboxsync if (conn->io != NULL)
7c90a188b164765cebe27fa754d68a4321ded83evboxsync conn->io = io_loop_move_io(&conn->io);
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync if (conn->to != NULL)
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync conn->to = io_loop_move_timeout(&conn->to);
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync if (conn->input != NULL)
7c90a188b164765cebe27fa754d68a4321ded83evboxsync i_stream_switch_ioloop(conn->input);
7c90a188b164765cebe27fa754d68a4321ded83evboxsync if (conn->output != NULL)
7c90a188b164765cebe27fa754d68a4321ded83evboxsync o_stream_switch_ioloop(conn->output);
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync}
7c90a188b164765cebe27fa754d68a4321ded83evboxsync
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsyncstruct connection_list *
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsyncconnection_list_init(const struct connection_settings *set,
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync const struct connection_vfuncs *vfuncs)
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync{
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync struct connection_list *list;
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync i_assert(vfuncs->input != NULL ||
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync set->input_full_behavior != CONNECTION_BEHAVIOR_ALLOW);
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync i_assert(set->major_version == 0 ||
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync (set->service_name_in != NULL &&
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync set->service_name_out != NULL));
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync list = i_new(struct connection_list, 1);
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync list->set = *set;
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync list->v = *vfuncs;
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync if (list->v.input == NULL)
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync list->v.input = connection_input_default;
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync if (list->v.input_line == NULL)
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync list->v.input_line = connection_input_line_default;
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync return list;
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync}
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsyncvoid connection_list_deinit(struct connection_list **_list)
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync{
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync struct connection_list *list = *_list;
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync struct connection *conn;
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync *_list = NULL;
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync while (list->connections != NULL) {
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync conn = list->connections;
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync conn->disconnect_reason = CONNECTION_DISCONNECT_DEINIT;
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync list->v.destroy(conn);
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync i_assert(conn != list->connections);
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync }
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync i_free(list);
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync}
2e848e79ccf2e4285250a0af98ddb9eb28864878vboxsync