connection.c revision d951320d498ae0800b677b754dde71574102123b
02c335c23bf5fa225a467c19f2c063fb0dc7b8c3Timo Sirainen/* Copyright (c) 2013-2016 Dovecot authors, see the included COPYING file */
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen#include "lib.h"
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen#include "ioloop.h"
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen#include "istream.h"
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen#include "ostream.h"
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen#include "iostream.h"
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch#include "net.h"
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch#include "strescape.h"
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch#include "llist.h"
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch#include "time-util.h"
c215ca02d468b0e542523df1ed18e5f2d7e63968Timo Sirainen#include "connection.h"
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen#include <unistd.h>
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainenstatic void connection_idle_timeout(struct connection *conn)
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen{
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen conn->disconnect_reason = CONNECTION_DISCONNECT_IDLE_TIMEOUT;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen conn->list->v.destroy(conn);
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen}
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainenstatic void connection_connect_timeout(struct connection *conn)
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen{
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen conn->disconnect_reason = CONNECTION_DISCONNECT_CONNECT_TIMEOUT;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen conn->list->v.destroy(conn);
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen}
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainenvoid connection_input_default(struct connection *conn)
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen{
b8835b8a21c617ceb82ddc5a176243faf36aa8f7Timo Sirainen const char *line;
34a41fd572d2516549b3a3b340c36730f284612aTimo Sirainen struct istream *input;
34a41fd572d2516549b3a3b340c36730f284612aTimo Sirainen struct ostream *output;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen int ret = 0;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen switch (connection_input_read(conn)) {
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen case -1:
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen return;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen case 0: /* allow calling this function for buffered input */
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen case 1:
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen break;
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen default:
b8835b8a21c617ceb82ddc5a176243faf36aa8f7Timo Sirainen i_unreached();
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen }
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen input = conn->input;
678d0463849ba777106eb7875f27db07a5d8e3dfTimo Sirainen output = conn->output;
4ee00532a265bdfb38539d811fcd12d51210ac35Timo Sirainen i_stream_ref(input);
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen if (output != NULL) {
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen o_stream_ref(output);
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen o_stream_cork(output);
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen }
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch while (!input->closed && (line = i_stream_next_line(input)) != NULL) {
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch T_BEGIN {
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen ret = conn->list->v.input_line(conn, line);
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen } T_END;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen if (ret <= 0)
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen break;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen }
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen if (output != NULL) {
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen o_stream_uncork(output);
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch o_stream_unref(&output);
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch }
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch if (ret < 0 && !input->closed) {
c649139f889c02154fc9a153728b81619edb5663Timo Sirainen conn->disconnect_reason = CONNECTION_DISCONNECT_DEINIT;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen conn->list->v.destroy(conn);
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch }
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch i_stream_unref(&input);
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch}
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Boschint connection_verify_version(struct connection *conn,
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen const char *const *args)
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen{
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen unsigned int recv_major_version;
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen /* VERSION <tab> service_name <tab> major version <tab> minor version */
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen if (str_array_length(args) != 4 ||
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen strcmp(args[0], "VERSION") != 0 ||
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen str_to_uint(args[2], &recv_major_version) < 0 ||
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen str_to_uint(args[3], &conn->minor_version) < 0) {
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen i_error("%s didn't reply with a valid VERSION line",
df1713bd29d29a3e3f3ebfdf05f929525825a7d3Timo Sirainen conn->name);
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen return -1;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen }
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen if (strcmp(args[1], conn->list->set.service_name_in) != 0) {
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen i_error("%s: Connected to wrong socket type. "
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen "We want '%s', but received '%s'", conn->name,
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen conn->list->set.service_name_in, args[1]);
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen return -1;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen }
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
df1713bd29d29a3e3f3ebfdf05f929525825a7d3Timo Sirainen if (recv_major_version != conn->list->set.major_version) {
df1713bd29d29a3e3f3ebfdf05f929525825a7d3Timo Sirainen i_error("%s: Socket supports major version %u, "
df1713bd29d29a3e3f3ebfdf05f929525825a7d3Timo Sirainen "but we support only %u (mixed old and new binaries?)",
cd2fc7dd28c3a2e3f82e8480eaf3ba7c4abc3614Timo Sirainen conn->name, recv_major_version,
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen conn->list->set.major_version);
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen return -1;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen }
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen return 0;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen}
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Boschint connection_input_line_default(struct connection *conn, const char *line)
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch{
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen const char *const *args;
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch args = t_strsplit_tabescaped(line);
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch if (!conn->version_received) {
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch if (connection_verify_version(conn, args) < 0)
c649139f889c02154fc9a153728b81619edb5663Timo Sirainen return -1;
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch conn->version_received = TRUE;
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch return 1;
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch }
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch return conn->list->v.input_args(conn, args);
c649139f889c02154fc9a153728b81619edb5663Timo Sirainen}
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainenstatic void connection_init_streams(struct connection *conn)
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch{
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch const struct connection_settings *set = &conn->list->set;
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch i_assert(conn->io == NULL);
53ec1ff2231d477db3103c51987fa9cb6033bc16Timo Sirainen i_assert(conn->input == NULL);
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen i_assert(conn->output == NULL);
c215ca02d468b0e542523df1ed18e5f2d7e63968Timo Sirainen i_assert(conn->to == NULL);
c215ca02d468b0e542523df1ed18e5f2d7e63968Timo Sirainen
c215ca02d468b0e542523df1ed18e5f2d7e63968Timo Sirainen conn->version_received = set->major_version == 0;
c215ca02d468b0e542523df1ed18e5f2d7e63968Timo Sirainen
c215ca02d468b0e542523df1ed18e5f2d7e63968Timo Sirainen if (set->input_max_size != 0) {
c215ca02d468b0e542523df1ed18e5f2d7e63968Timo Sirainen conn->input = i_stream_create_fd(conn->fd_in,
c215ca02d468b0e542523df1ed18e5f2d7e63968Timo Sirainen set->input_max_size);
c215ca02d468b0e542523df1ed18e5f2d7e63968Timo Sirainen i_stream_set_name(conn->input, conn->name);
88b90ce9dfe1056d1ec5497b95592d30a849e5f1Timo Sirainen conn->io = io_add_istream(conn->input, *conn->list->v.input, conn);
88b90ce9dfe1056d1ec5497b95592d30a849e5f1Timo Sirainen } else {
c215ca02d468b0e542523df1ed18e5f2d7e63968Timo Sirainen conn->io = io_add(conn->fd_in, IO_READ, *conn->list->v.input, conn);
c215ca02d468b0e542523df1ed18e5f2d7e63968Timo Sirainen }
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen if (set->output_max_size != 0) {
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen conn->output = o_stream_create_fd(conn->fd_out,
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen set->output_max_size);
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen o_stream_set_no_error_handling(conn->output, TRUE);
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen o_stream_set_name(conn->output, conn->name);
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen }
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch if (set->input_idle_timeout_secs != 0) {
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch conn->to = timeout_add(set->input_idle_timeout_secs*1000,
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen connection_idle_timeout, conn);
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen }
f7fa93fb42a5b9d4a7e2f0367f03f920ef7ec443Timo Sirainen if (set->major_version != 0 && !set->dont_send_version) {
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen o_stream_nsend_str(conn->output, t_strdup_printf(
f7fa93fb42a5b9d4a7e2f0367f03f920ef7ec443Timo Sirainen "VERSION\t%s\t%u\t%u\n", set->service_name_out,
f7fa93fb42a5b9d4a7e2f0367f03f920ef7ec443Timo Sirainen set->major_version, set->minor_version));
f7fa93fb42a5b9d4a7e2f0367f03f920ef7ec443Timo Sirainen }
dafbec2c6b4275233a78cb137f41dd8041aa1c46Timo Sirainen}
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Boschstatic void connection_client_connected(struct connection *conn, bool success)
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen{
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen i_assert(conn->list->set.client);
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen conn->connect_finished = ioloop_timeval;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen if (success)
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen connection_init_streams(conn);
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen if (conn->list->v.client_connected != NULL)
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen conn->list->v.client_connected(conn, success);
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen if (!success) {
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen conn->disconnect_reason =
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen CONNECTION_DISCONNECT_CONN_CLOSED;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen conn->list->v.destroy(conn);
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen }
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen}
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainenvoid connection_init_server(struct connection_list *list,
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen struct connection *conn, const char *name,
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen int fd_in, int fd_out)
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen{
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen i_assert(name != NULL);
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen i_assert(!list->set.client);
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen conn->list = list;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen conn->name = i_strdup(name);
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen conn->fd_in = fd_in;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen conn->fd_out = fd_out;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen connection_init_streams(conn);
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen DLLIST_PREPEND(&list->connections, conn);
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen list->connections_count++;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen}
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainenvoid connection_init_client_ip(struct connection_list *list,
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen struct connection *conn,
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen const struct ip_addr *ip, in_port_t port)
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen{
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen i_assert(list->set.client);
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen conn->fd_in = conn->fd_out = -1;
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen conn->list = list;
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen conn->name = i_strdup_printf("%s:%u", net_ip2addr(ip), port);
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen
b8835b8a21c617ceb82ddc5a176243faf36aa8f7Timo Sirainen conn->ip = *ip;
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen conn->port = port;
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen DLLIST_PREPEND(&list->connections, conn);
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen list->connections_count++;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen}
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainenvoid connection_init_client_unix(struct connection_list *list,
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen struct connection *conn, const char *path)
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen{
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen i_assert(list->set.client);
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen
b8835b8a21c617ceb82ddc5a176243faf36aa8f7Timo Sirainen conn->fd_in = conn->fd_out = -1;
b8835b8a21c617ceb82ddc5a176243faf36aa8f7Timo Sirainen conn->list = list;
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen conn->name = i_strdup(path);
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen DLLIST_PREPEND(&list->connections, conn);
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen list->connections_count++;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen}
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainenvoid connection_init_from_streams(struct connection_list *list,
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen struct connection *conn, const char *name,
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen struct istream *input, struct ostream *output)
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen{
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen i_assert(name != NULL);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen conn->list = list;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen conn->name = i_strdup(name);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen conn->fd_in = i_stream_get_fd(input);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen conn->fd_out = o_stream_get_fd(output);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen i_assert(conn->fd_in >= 0);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen i_assert(conn->fd_out >= 0);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen i_assert(conn->io == NULL);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen i_assert(conn->input == NULL);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen i_assert(conn->output == NULL);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen i_assert(conn->to == NULL);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen conn->input = input;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen i_stream_ref(conn->input);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen i_stream_set_name(conn->input, conn->name);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen conn->output = output;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen o_stream_ref(conn->output);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen o_stream_set_no_error_handling(conn->output, TRUE);
34a41fd572d2516549b3a3b340c36730f284612aTimo Sirainen o_stream_set_name(conn->output, conn->name);
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen conn->io = io_add_istream(conn->input, *list->v.input, conn);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen DLLIST_PREPEND(&list->connections, conn);
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen list->connections_count++;
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen
34a41fd572d2516549b3a3b340c36730f284612aTimo Sirainen if (list->v.client_connected != NULL)
34a41fd572d2516549b3a3b340c36730f284612aTimo Sirainen list->v.client_connected(conn, TRUE);
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen}
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainenstatic void connection_socket_connected(struct connection *conn)
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen{
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen io_remove(&conn->io);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen if (conn->to != NULL)
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen timeout_remove(&conn->to);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen errno = net_geterror(conn->fd_in);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen connection_client_connected(conn, errno == 0);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen}
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainenint connection_client_connect(struct connection *conn)
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen{
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen const struct connection_settings *set = &conn->list->set;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen int fd;
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen i_assert(conn->list->set.client);
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen i_assert(conn->fd_in == -1);
91c58af8e992d028eb325707904debb58ae80438Timo Sirainen
91c58af8e992d028eb325707904debb58ae80438Timo Sirainen if (conn->port != 0)
91c58af8e992d028eb325707904debb58ae80438Timo Sirainen fd = net_connect_ip(&conn->ip, conn->port, NULL);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen else if (conn->list->set.unix_client_connect_msecs == 0)
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen fd = net_connect_unix(conn->name);
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen else
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen fd = net_connect_unix_with_retries(conn->name, conn->list->set.unix_client_connect_msecs);
34a41fd572d2516549b3a3b340c36730f284612aTimo Sirainen if (fd == -1)
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen return -1;
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen conn->fd_in = conn->fd_out = fd;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen conn->connect_started = ioloop_timeval;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen if (conn->port != 0 ||
34a41fd572d2516549b3a3b340c36730f284612aTimo Sirainen conn->list->set.delayed_unix_client_connected_callback) {
34a41fd572d2516549b3a3b340c36730f284612aTimo Sirainen conn->io = io_add(conn->fd_out, IO_WRITE,
34a41fd572d2516549b3a3b340c36730f284612aTimo Sirainen connection_socket_connected, conn);
34a41fd572d2516549b3a3b340c36730f284612aTimo Sirainen if (set->client_connect_timeout_msecs != 0) {
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen conn->to = timeout_add(set->client_connect_timeout_msecs,
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen connection_connect_timeout, conn);
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen }
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen } else {
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen connection_client_connected(conn, TRUE);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen }
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen return 0;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen}
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainenvoid connection_disconnect(struct connection *conn)
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen{
34a41fd572d2516549b3a3b340c36730f284612aTimo Sirainen conn->last_input = 0;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen memset(&conn->last_input_tv, 0, sizeof(conn->last_input_tv));
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen if (conn->to != NULL)
34a41fd572d2516549b3a3b340c36730f284612aTimo Sirainen timeout_remove(&conn->to);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen if (conn->io != NULL)
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen io_remove(&conn->io);
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen if (conn->input != NULL) {
34a41fd572d2516549b3a3b340c36730f284612aTimo Sirainen i_stream_close(conn->input);
34a41fd572d2516549b3a3b340c36730f284612aTimo Sirainen i_stream_destroy(&conn->input);
34a41fd572d2516549b3a3b340c36730f284612aTimo Sirainen }
34a41fd572d2516549b3a3b340c36730f284612aTimo Sirainen if (conn->output != NULL) {
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen o_stream_close(conn->output);
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen o_stream_destroy(&conn->output);
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen }
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen if (conn->fd_in != -1) {
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen if (close(conn->fd_in) < 0)
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen i_error("close(%s) failed: %m", conn->name);
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen if (conn->fd_in != conn->fd_out && close(conn->fd_out) < 0)
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen i_error("close(%s/out) failed: %m", conn->name);
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen conn->fd_in = conn->fd_out = -1;
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen }
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen}
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainenvoid connection_deinit(struct connection *conn)
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen{
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen i_assert(conn->list->connections_count > 0);
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen conn->list->connections_count--;
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen DLLIST_REMOVE(&conn->list->connections, conn);
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen connection_disconnect(conn);
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen i_free(conn->name);
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen}
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainenint connection_input_read(struct connection *conn)
acc4e0a41f1c8ef0559a19c280afc1b97b9e0818Timo Sirainen{
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen conn->last_input = ioloop_time;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen conn->last_input_tv = ioloop_timeval;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen if (conn->to != NULL)
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen timeout_reset(conn->to);
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
34a41fd572d2516549b3a3b340c36730f284612aTimo Sirainen switch (i_stream_read(conn->input)) {
34a41fd572d2516549b3a3b340c36730f284612aTimo Sirainen case -2:
34a41fd572d2516549b3a3b340c36730f284612aTimo Sirainen /* buffer full */
34a41fd572d2516549b3a3b340c36730f284612aTimo Sirainen switch (conn->list->set.input_full_behavior) {
34a41fd572d2516549b3a3b340c36730f284612aTimo Sirainen case CONNECTION_BEHAVIOR_DESTROY:
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen conn->disconnect_reason =
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen CONNECTION_DISCONNECT_BUFFER_FULL;
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen conn->list->v.destroy(conn);
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen return -1;
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen case CONNECTION_BEHAVIOR_ALLOW:
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen return -2;
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen }
acc4e0a41f1c8ef0559a19c280afc1b97b9e0818Timo Sirainen i_unreached();
acc4e0a41f1c8ef0559a19c280afc1b97b9e0818Timo Sirainen case -1:
acc4e0a41f1c8ef0559a19c280afc1b97b9e0818Timo Sirainen /* disconnected */
acc4e0a41f1c8ef0559a19c280afc1b97b9e0818Timo Sirainen conn->disconnect_reason =
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen CONNECTION_DISCONNECT_CONN_CLOSED;
acc4e0a41f1c8ef0559a19c280afc1b97b9e0818Timo Sirainen conn->list->v.destroy(conn);
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen return -1;
b8835b8a21c617ceb82ddc5a176243faf36aa8f7Timo Sirainen case 0:
b8835b8a21c617ceb82ddc5a176243faf36aa8f7Timo Sirainen /* nothing new read */
b8835b8a21c617ceb82ddc5a176243faf36aa8f7Timo Sirainen return 0;
b8835b8a21c617ceb82ddc5a176243faf36aa8f7Timo Sirainen default:
b8835b8a21c617ceb82ddc5a176243faf36aa8f7Timo Sirainen /* something was read */
b8835b8a21c617ceb82ddc5a176243faf36aa8f7Timo Sirainen return 1;
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen }
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen}
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainenconst char *connection_disconnect_reason(struct connection *conn)
34a41fd572d2516549b3a3b340c36730f284612aTimo Sirainen{
34a41fd572d2516549b3a3b340c36730f284612aTimo Sirainen switch (conn->disconnect_reason) {
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen case CONNECTION_DISCONNECT_DEINIT:
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen return "Deinitializing";
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen case CONNECTION_DISCONNECT_CONNECT_TIMEOUT: {
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch unsigned int msecs =
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch conn->list->set.client_connect_timeout_msecs;
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch return t_strdup_printf("connect() timed out in %u.%03u secs",
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch msecs/1000, msecs%1000);
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch }
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch case CONNECTION_DISCONNECT_IDLE_TIMEOUT:
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch return "Idle timeout";
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch case CONNECTION_DISCONNECT_CONN_CLOSED:
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch if (conn->input == NULL)
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch return t_strdup_printf("connect() failed: %m");
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch /* fall through */
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch case CONNECTION_DISCONNECT_NOT:
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch case CONNECTION_DISCONNECT_BUFFER_FULL:
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch return io_stream_get_disconnect_reason(conn->input, conn->output);
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch }
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch i_unreached();
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch}
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Boschconst char *connection_input_timeout_reason(struct connection *conn)
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch{
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch if (conn->last_input_tv.tv_sec != 0) {
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch int diff = timeval_diff_msecs(&ioloop_timeval, &conn->last_input_tv);
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch return t_strdup_printf("No input for %u.%03u secs",
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch diff/1000, diff%1000);
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch } else if (conn->connect_finished.tv_sec != 0) {
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch int diff = timeval_diff_msecs(&ioloop_timeval, &conn->connect_finished);
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch return t_strdup_printf(
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch "No input since connected %u.%03u secs ago",
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch diff/1000, diff%1000);
1a115c1eb46e9103f81228dde272852cb78ed4b5Timo Sirainen } else {
1a115c1eb46e9103f81228dde272852cb78ed4b5Timo Sirainen int diff = timeval_diff_msecs(&ioloop_timeval, &conn->connect_started);
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch return t_strdup_printf("connect() timed out after %u.%03u secs",
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch diff/1000, diff%1000);
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch }
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch}
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Boschvoid connection_switch_ioloop(struct connection *conn)
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch{
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch if (conn->io != NULL)
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch conn->io = io_loop_move_io(&conn->io);
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch if (conn->to != NULL)
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch conn->to = io_loop_move_timeout(&conn->to);
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch if (conn->input != NULL)
9937dfc157dc64ed781b7aa264aa893d1d50c5c4Timo Sirainen i_stream_switch_ioloop(conn->input);
9937dfc157dc64ed781b7aa264aa893d1d50c5c4Timo Sirainen if (conn->output != NULL)
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch o_stream_switch_ioloop(conn->output);
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch}
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainenstruct connection_list *
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainenconnection_list_init(const struct connection_settings *set,
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen const struct connection_vfuncs *vfuncs)
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen{
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch struct connection_list *list;
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen i_assert(vfuncs->input != NULL ||
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen set->input_full_behavior != CONNECTION_BEHAVIOR_ALLOW);
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen i_assert(set->major_version == 0 ||
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen (set->service_name_in != NULL &&
678d0463849ba777106eb7875f27db07a5d8e3dfTimo Sirainen set->service_name_out != NULL));
678d0463849ba777106eb7875f27db07a5d8e3dfTimo Sirainen
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen list = i_new(struct connection_list, 1);
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen list->set = *set;
c649139f889c02154fc9a153728b81619edb5663Timo Sirainen list->v = *vfuncs;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
6b09a3b269f4b10364c9a77f6614dbe3d306b79dTimo Sirainen if (list->v.input == NULL)
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen list->v.input = connection_input_default;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen if (list->v.input_line == NULL)
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen list->v.input_line = connection_input_line_default;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen return list;
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch}
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
c215ca02d468b0e542523df1ed18e5f2d7e63968Timo Sirainenvoid connection_list_deinit(struct connection_list **_list)
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch{
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch struct connection_list *list = *_list;
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch struct connection *conn;
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch *_list = NULL;
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch while (list->connections != NULL) {
c215ca02d468b0e542523df1ed18e5f2d7e63968Timo Sirainen conn = list->connections;
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch conn->disconnect_reason = CONNECTION_DISCONNECT_DEINIT;
34a41fd572d2516549b3a3b340c36730f284612aTimo Sirainen list->v.destroy(conn);
34a41fd572d2516549b3a3b340c36730f284612aTimo Sirainen i_assert(conn != list->connections);
428d63767dc20aeb87695b82fb01cd0a06d7769cTimo Sirainen }
2d7df7973f80011033e8e9fa676d3ff4c14468d8Stephan Bosch i_free(list);
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen}
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen