bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2013-2018 Dovecot authors, see the included COPYING file */
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen#include "lib.h"
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen#include "ioloop.h"
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen#include "istream.h"
fa33df8230c2f27ae863ff83d4251923428d53c7Aki Tuomi#include "istream-unix.h"
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen#include "ostream.h"
fa33df8230c2f27ae863ff83d4251923428d53c7Aki Tuomi#include "ostream-unix.h"
c5f932968281763df360b9c97cef60f5f80d5e3dTimo Sirainen#include "iostream.h"
bdd36cfdba3ff66d25570a9ff568d69e1eb543cfTimo Sirainen#include "net.h"
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen#include "strescape.h"
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen#include "llist.h"
d951320d498ae0800b677b754dde71574102123bTimo Sirainen#include "time-util.h"
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen#include "connection.h"
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen#include <unistd.h>
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainenstatic void connection_idle_timeout(struct connection *conn)
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen{
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen conn->disconnect_reason = CONNECTION_DISCONNECT_IDLE_TIMEOUT;
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen conn->list->v.destroy(conn);
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen}
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainenstatic void connection_connect_timeout(struct connection *conn)
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen{
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen conn->disconnect_reason = CONNECTION_DISCONNECT_CONNECT_TIMEOUT;
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen conn->list->v.destroy(conn);
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen}
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainenvoid connection_input_default(struct connection *conn)
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen{
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen const char *line;
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen struct istream *input;
091a2dea9d89734a7c1225eed511b3851693a757Timo Sirainen struct ostream *output;
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen int ret = 0;
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen switch (connection_input_read(conn)) {
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen case -1:
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen return;
a21f618de284dc22a480af1371d5f5cea50a39dfTimo Sirainen case 0: /* allow calling this function for buffered input */
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen case 1:
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen break;
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen default:
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen i_unreached();
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen }
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen input = conn->input;
091a2dea9d89734a7c1225eed511b3851693a757Timo Sirainen output = conn->output;
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen i_stream_ref(input);
091a2dea9d89734a7c1225eed511b3851693a757Timo Sirainen if (output != NULL) {
091a2dea9d89734a7c1225eed511b3851693a757Timo Sirainen o_stream_ref(output);
091a2dea9d89734a7c1225eed511b3851693a757Timo Sirainen o_stream_cork(output);
091a2dea9d89734a7c1225eed511b3851693a757Timo Sirainen }
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen while (!input->closed && (line = i_stream_next_line(input)) != NULL) {
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen T_BEGIN {
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen ret = conn->list->v.input_line(conn, line);
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen } T_END;
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen if (ret <= 0)
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen break;
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen }
091a2dea9d89734a7c1225eed511b3851693a757Timo Sirainen if (output != NULL) {
091a2dea9d89734a7c1225eed511b3851693a757Timo Sirainen o_stream_uncork(output);
091a2dea9d89734a7c1225eed511b3851693a757Timo Sirainen o_stream_unref(&output);
091a2dea9d89734a7c1225eed511b3851693a757Timo Sirainen }
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen if (ret < 0 && !input->closed) {
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen conn->disconnect_reason = CONNECTION_DISCONNECT_DEINIT;
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen conn->list->v.destroy(conn);
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen }
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen i_stream_unref(&input);
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen}
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainenint connection_verify_version(struct connection *conn,
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen const char *const *args)
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen{
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen unsigned int recv_major_version;
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen /* VERSION <tab> service_name <tab> major version <tab> minor version */
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen if (str_array_length(args) != 4 ||
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen strcmp(args[0], "VERSION") != 0 ||
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen str_to_uint(args[2], &recv_major_version) < 0 ||
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen str_to_uint(args[3], &conn->minor_version) < 0) {
15dd18994a8a4933e39e2f87233255d0ca82ba3eTimo Sirainen i_error("%s didn't reply with a valid VERSION line: %s",
15dd18994a8a4933e39e2f87233255d0ca82ba3eTimo Sirainen conn->name, t_strarray_join(args, "\t"));
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen return -1;
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen }
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen if (strcmp(args[1], conn->list->set.service_name_in) != 0) {
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen i_error("%s: Connected to wrong socket type. "
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen "We want '%s', but received '%s'", conn->name,
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen conn->list->set.service_name_in, args[1]);
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen return -1;
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen }
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen if (recv_major_version != conn->list->set.major_version) {
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen i_error("%s: Socket supports major version %u, "
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen "but we support only %u (mixed old and new binaries?)",
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen conn->name, recv_major_version,
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen conn->list->set.major_version);
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen return -1;
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen }
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen return 0;
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen}
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainenint connection_input_line_default(struct connection *conn, const char *line)
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen{
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen const char *const *args;
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen args = t_strsplit_tabescaped(line);
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen if (!conn->version_received) {
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen if (connection_verify_version(conn, args) < 0)
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen return -1;
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen conn->version_received = TRUE;
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen return 1;
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen }
a5b64f1abb1cb0a9718d5bf7f0ae808072237259Timo Sirainen if (args[0] == NULL && !conn->list->set.allow_empty_args_input) {
a5b64f1abb1cb0a9718d5bf7f0ae808072237259Timo Sirainen i_error("%s: Unexpectedly received empty line", conn->name);
a5b64f1abb1cb0a9718d5bf7f0ae808072237259Timo Sirainen return -1;
a5b64f1abb1cb0a9718d5bf7f0ae808072237259Timo Sirainen }
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen return conn->list->v.input_args(conn, args);
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen}
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen
c85f67cfb8e1cef2de2b681debf4703d5818dc01Stephan Boschvoid connection_input_halt(struct connection *conn)
c85f67cfb8e1cef2de2b681debf4703d5818dc01Stephan Bosch{
c85f67cfb8e1cef2de2b681debf4703d5818dc01Stephan Bosch io_remove(&conn->io);
c85f67cfb8e1cef2de2b681debf4703d5818dc01Stephan Bosch}
c85f67cfb8e1cef2de2b681debf4703d5818dc01Stephan Bosch
c85f67cfb8e1cef2de2b681debf4703d5818dc01Stephan Boschvoid connection_input_resume(struct connection *conn)
c85f67cfb8e1cef2de2b681debf4703d5818dc01Stephan Bosch{
c85f67cfb8e1cef2de2b681debf4703d5818dc01Stephan Bosch const struct connection_settings *set = &conn->list->set;
c85f67cfb8e1cef2de2b681debf4703d5818dc01Stephan Bosch
c85f67cfb8e1cef2de2b681debf4703d5818dc01Stephan Bosch if (conn->io != NULL)
c85f67cfb8e1cef2de2b681debf4703d5818dc01Stephan Bosch return;
c85f67cfb8e1cef2de2b681debf4703d5818dc01Stephan Bosch if (conn->from_streams || set->input_max_size != 0) {
c85f67cfb8e1cef2de2b681debf4703d5818dc01Stephan Bosch conn->io = io_add_istream_to(conn->ioloop, conn->input,
c85f67cfb8e1cef2de2b681debf4703d5818dc01Stephan Bosch *conn->list->v.input, conn);
c85f67cfb8e1cef2de2b681debf4703d5818dc01Stephan Bosch } else {
c85f67cfb8e1cef2de2b681debf4703d5818dc01Stephan Bosch conn->io = io_add_to(conn->ioloop, conn->fd_in, IO_READ,
c85f67cfb8e1cef2de2b681debf4703d5818dc01Stephan Bosch *conn->list->v.input, conn);
c85f67cfb8e1cef2de2b681debf4703d5818dc01Stephan Bosch }
c85f67cfb8e1cef2de2b681debf4703d5818dc01Stephan Bosch}
c85f67cfb8e1cef2de2b681debf4703d5818dc01Stephan Bosch
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainenstatic void connection_init_streams(struct connection *conn)
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen{
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen const struct connection_settings *set = &conn->list->set;
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen i_assert(conn->io == NULL);
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen i_assert(conn->input == NULL);
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen i_assert(conn->output == NULL);
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen i_assert(conn->to == NULL);
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen conn->version_received = set->major_version == 0;
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen if (set->input_max_size != 0) {
fa33df8230c2f27ae863ff83d4251923428d53c7Aki Tuomi if (conn->unix_socket)
fa33df8230c2f27ae863ff83d4251923428d53c7Aki Tuomi conn->input = i_stream_create_unix(conn->fd_in,
fa33df8230c2f27ae863ff83d4251923428d53c7Aki Tuomi set->input_max_size);
fa33df8230c2f27ae863ff83d4251923428d53c7Aki Tuomi else
fa33df8230c2f27ae863ff83d4251923428d53c7Aki Tuomi conn->input = i_stream_create_fd(conn->fd_in,
fa33df8230c2f27ae863ff83d4251923428d53c7Aki Tuomi set->input_max_size);
d48e40d6c77d673ad402d96571198d1cce4da225Timo Sirainen i_stream_set_name(conn->input, conn->name);
36e5cd9ab4c86cf9da0762fa327cd5be04397676Aki Tuomi i_stream_switch_ioloop_to(conn->input, conn->ioloop);
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen }
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen if (set->output_max_size != 0) {
fa33df8230c2f27ae863ff83d4251923428d53c7Aki Tuomi if (conn->unix_socket)
fa33df8230c2f27ae863ff83d4251923428d53c7Aki Tuomi conn->output = o_stream_create_unix(conn->fd_out,
fa33df8230c2f27ae863ff83d4251923428d53c7Aki Tuomi set->output_max_size);
fa33df8230c2f27ae863ff83d4251923428d53c7Aki Tuomi else
fa33df8230c2f27ae863ff83d4251923428d53c7Aki Tuomi conn->output = o_stream_create_fd(conn->fd_out,
fa33df8230c2f27ae863ff83d4251923428d53c7Aki Tuomi set->output_max_size);
a327d9301f593433c228c4cc8cca05c95b37f6fbTimo Sirainen o_stream_set_no_error_handling(conn->output, TRUE);
8a4a0ef8264d95ffb2ba8f6f109f94ea7f3454e8Timo Sirainen o_stream_set_finish_via_child(conn->output, FALSE);
d48e40d6c77d673ad402d96571198d1cce4da225Timo Sirainen o_stream_set_name(conn->output, conn->name);
36e5cd9ab4c86cf9da0762fa327cd5be04397676Aki Tuomi o_stream_switch_ioloop_to(conn->output, conn->ioloop);
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen }
c85f67cfb8e1cef2de2b681debf4703d5818dc01Stephan Bosch connection_input_resume(conn);
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen if (set->input_idle_timeout_secs != 0) {
086b73efd1a5812a64acc951366a499d325509a6Stephan Bosch conn->to = timeout_add_to(conn->ioloop,
086b73efd1a5812a64acc951366a499d325509a6Stephan Bosch set->input_idle_timeout_secs*1000,
086b73efd1a5812a64acc951366a499d325509a6Stephan Bosch connection_idle_timeout, conn);
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen }
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen if (set->major_version != 0 && !set->dont_send_version) {
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen o_stream_nsend_str(conn->output, t_strdup_printf(
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen "VERSION\t%s\t%u\t%u\n", set->service_name_out,
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen set->major_version, set->minor_version));
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen }
7db7fbea5d8a07463b625f93d69166d56018dadfTimo Sirainen}
7db7fbea5d8a07463b625f93d69166d56018dadfTimo Sirainen
ed567dac7e55ab3e8dd53d9c86c31ebb2032d4dfTimo Sirainenvoid connection_streams_changed(struct connection *conn)
ed567dac7e55ab3e8dd53d9c86c31ebb2032d4dfTimo Sirainen{
ed567dac7e55ab3e8dd53d9c86c31ebb2032d4dfTimo Sirainen const struct connection_settings *set = &conn->list->set;
ed567dac7e55ab3e8dd53d9c86c31ebb2032d4dfTimo Sirainen
ed567dac7e55ab3e8dd53d9c86c31ebb2032d4dfTimo Sirainen if (set->input_max_size != 0 && conn->io != NULL) {
c85f67cfb8e1cef2de2b681debf4703d5818dc01Stephan Bosch connection_input_halt(conn);
c85f67cfb8e1cef2de2b681debf4703d5818dc01Stephan Bosch connection_input_resume(conn);
ed567dac7e55ab3e8dd53d9c86c31ebb2032d4dfTimo Sirainen }
ed567dac7e55ab3e8dd53d9c86c31ebb2032d4dfTimo Sirainen}
ed567dac7e55ab3e8dd53d9c86c31ebb2032d4dfTimo Sirainen
7db7fbea5d8a07463b625f93d69166d56018dadfTimo Sirainenstatic void connection_client_connected(struct connection *conn, bool success)
7db7fbea5d8a07463b625f93d69166d56018dadfTimo Sirainen{
7db7fbea5d8a07463b625f93d69166d56018dadfTimo Sirainen i_assert(conn->list->set.client);
7db7fbea5d8a07463b625f93d69166d56018dadfTimo Sirainen
2c5c70e12365d7910848259f88eb237ce3a15947Timo Sirainen conn->connect_finished = ioloop_timeval;
7db7fbea5d8a07463b625f93d69166d56018dadfTimo Sirainen if (success)
7db7fbea5d8a07463b625f93d69166d56018dadfTimo Sirainen connection_init_streams(conn);
7db7fbea5d8a07463b625f93d69166d56018dadfTimo Sirainen if (conn->list->v.client_connected != NULL)
7db7fbea5d8a07463b625f93d69166d56018dadfTimo Sirainen conn->list->v.client_connected(conn, success);
7db7fbea5d8a07463b625f93d69166d56018dadfTimo Sirainen if (!success) {
7db7fbea5d8a07463b625f93d69166d56018dadfTimo Sirainen conn->disconnect_reason =
7db7fbea5d8a07463b625f93d69166d56018dadfTimo Sirainen CONNECTION_DISCONNECT_CONN_CLOSED;
7db7fbea5d8a07463b625f93d69166d56018dadfTimo Sirainen conn->list->v.destroy(conn);
7db7fbea5d8a07463b625f93d69166d56018dadfTimo Sirainen }
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen}
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen
4b9e7a8752803928aa0897f8cc1fc34592452f07Stephan Boschvoid connection_init(struct connection_list *list,
4b9e7a8752803928aa0897f8cc1fc34592452f07Stephan Bosch struct connection *conn)
4b9e7a8752803928aa0897f8cc1fc34592452f07Stephan Bosch{
086b73efd1a5812a64acc951366a499d325509a6Stephan Bosch conn->ioloop = current_ioloop;
4b9e7a8752803928aa0897f8cc1fc34592452f07Stephan Bosch conn->fd_in = -1;
4b9e7a8752803928aa0897f8cc1fc34592452f07Stephan Bosch conn->fd_out = -1;
4b9e7a8752803928aa0897f8cc1fc34592452f07Stephan Bosch conn->name = NULL;
4b9e7a8752803928aa0897f8cc1fc34592452f07Stephan Bosch
4b9e7a8752803928aa0897f8cc1fc34592452f07Stephan Bosch if (conn->list != NULL) {
4b9e7a8752803928aa0897f8cc1fc34592452f07Stephan Bosch i_assert(conn->list == list);
4b9e7a8752803928aa0897f8cc1fc34592452f07Stephan Bosch } else {
4b9e7a8752803928aa0897f8cc1fc34592452f07Stephan Bosch conn->list = list;
4b9e7a8752803928aa0897f8cc1fc34592452f07Stephan Bosch DLLIST_PREPEND(&list->connections, conn);
4b9e7a8752803928aa0897f8cc1fc34592452f07Stephan Bosch list->connections_count++;
4b9e7a8752803928aa0897f8cc1fc34592452f07Stephan Bosch }
4b9e7a8752803928aa0897f8cc1fc34592452f07Stephan Bosch}
4b9e7a8752803928aa0897f8cc1fc34592452f07Stephan Bosch
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainenvoid connection_init_server(struct connection_list *list,
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen struct connection *conn, const char *name,
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen int fd_in, int fd_out)
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen{
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen i_assert(name != NULL);
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen i_assert(!list->set.client);
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen
4b9e7a8752803928aa0897f8cc1fc34592452f07Stephan Bosch connection_init(list, conn);
4b9e7a8752803928aa0897f8cc1fc34592452f07Stephan Bosch
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen conn->name = i_strdup(name);
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen conn->fd_in = fd_in;
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen conn->fd_out = fd_out;
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen connection_init_streams(conn);
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen}
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen
54c6a8135c0ded324f7ae7d0cdf1ef177004ee2dStephan Boschvoid connection_init_client_ip_from(struct connection_list *list,
54c6a8135c0ded324f7ae7d0cdf1ef177004ee2dStephan Bosch struct connection *conn,
54c6a8135c0ded324f7ae7d0cdf1ef177004ee2dStephan Bosch const struct ip_addr *ip, in_port_t port,
54c6a8135c0ded324f7ae7d0cdf1ef177004ee2dStephan Bosch const struct ip_addr *my_ip)
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen{
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen i_assert(list->set.client);
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen
4b9e7a8752803928aa0897f8cc1fc34592452f07Stephan Bosch connection_init(list, conn);
4b9e7a8752803928aa0897f8cc1fc34592452f07Stephan Bosch
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen conn->fd_in = conn->fd_out = -1;
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen conn->name = i_strdup_printf("%s:%u", net_ip2addr(ip), port);
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen conn->ip = *ip;
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen conn->port = port;
54c6a8135c0ded324f7ae7d0cdf1ef177004ee2dStephan Bosch
54c6a8135c0ded324f7ae7d0cdf1ef177004ee2dStephan Bosch if (my_ip != NULL)
54c6a8135c0ded324f7ae7d0cdf1ef177004ee2dStephan Bosch conn->my_ip = *my_ip;
54c6a8135c0ded324f7ae7d0cdf1ef177004ee2dStephan Bosch else
54c6a8135c0ded324f7ae7d0cdf1ef177004ee2dStephan Bosch i_zero(&conn->my_ip);
54c6a8135c0ded324f7ae7d0cdf1ef177004ee2dStephan Bosch}
54c6a8135c0ded324f7ae7d0cdf1ef177004ee2dStephan Bosch
54c6a8135c0ded324f7ae7d0cdf1ef177004ee2dStephan Boschvoid connection_init_client_ip(struct connection_list *list,
54c6a8135c0ded324f7ae7d0cdf1ef177004ee2dStephan Bosch struct connection *conn,
54c6a8135c0ded324f7ae7d0cdf1ef177004ee2dStephan Bosch const struct ip_addr *ip, in_port_t port)
54c6a8135c0ded324f7ae7d0cdf1ef177004ee2dStephan Bosch{
54c6a8135c0ded324f7ae7d0cdf1ef177004ee2dStephan Bosch connection_init_client_ip_from(list, conn, ip, port, NULL);
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen}
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainenvoid connection_init_client_unix(struct connection_list *list,
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen struct connection *conn, const char *path)
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen{
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen i_assert(list->set.client);
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen
4b9e7a8752803928aa0897f8cc1fc34592452f07Stephan Bosch connection_init(list, conn);
4b9e7a8752803928aa0897f8cc1fc34592452f07Stephan Bosch
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen conn->fd_in = conn->fd_out = -1;
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen conn->name = i_strdup(path);
fa33df8230c2f27ae863ff83d4251923428d53c7Aki Tuomi conn->unix_socket = TRUE;
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen}
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen
67e0afe62b26d222614b8d817155bf5c74bd7fe0Stephan Boschvoid connection_init_from_streams(struct connection_list *list,
67e0afe62b26d222614b8d817155bf5c74bd7fe0Stephan Bosch struct connection *conn, const char *name,
67e0afe62b26d222614b8d817155bf5c74bd7fe0Stephan Bosch struct istream *input, struct ostream *output)
67e0afe62b26d222614b8d817155bf5c74bd7fe0Stephan Bosch{
67e0afe62b26d222614b8d817155bf5c74bd7fe0Stephan Bosch i_assert(name != NULL);
67e0afe62b26d222614b8d817155bf5c74bd7fe0Stephan Bosch
4b9e7a8752803928aa0897f8cc1fc34592452f07Stephan Bosch connection_init(list, conn);
4b9e7a8752803928aa0897f8cc1fc34592452f07Stephan Bosch
67e0afe62b26d222614b8d817155bf5c74bd7fe0Stephan Bosch conn->name = i_strdup(name);
c85f67cfb8e1cef2de2b681debf4703d5818dc01Stephan Bosch conn->from_streams = TRUE;
67e0afe62b26d222614b8d817155bf5c74bd7fe0Stephan Bosch conn->fd_in = i_stream_get_fd(input);
67e0afe62b26d222614b8d817155bf5c74bd7fe0Stephan Bosch conn->fd_out = o_stream_get_fd(output);
67e0afe62b26d222614b8d817155bf5c74bd7fe0Stephan Bosch
67e0afe62b26d222614b8d817155bf5c74bd7fe0Stephan Bosch i_assert(conn->fd_in >= 0);
67e0afe62b26d222614b8d817155bf5c74bd7fe0Stephan Bosch i_assert(conn->fd_out >= 0);
67e0afe62b26d222614b8d817155bf5c74bd7fe0Stephan Bosch i_assert(conn->io == NULL);
67e0afe62b26d222614b8d817155bf5c74bd7fe0Stephan Bosch i_assert(conn->input == NULL);
67e0afe62b26d222614b8d817155bf5c74bd7fe0Stephan Bosch i_assert(conn->output == NULL);
67e0afe62b26d222614b8d817155bf5c74bd7fe0Stephan Bosch i_assert(conn->to == NULL);
67e0afe62b26d222614b8d817155bf5c74bd7fe0Stephan Bosch
67e0afe62b26d222614b8d817155bf5c74bd7fe0Stephan Bosch conn->input = input;
67e0afe62b26d222614b8d817155bf5c74bd7fe0Stephan Bosch i_stream_ref(conn->input);
67e0afe62b26d222614b8d817155bf5c74bd7fe0Stephan Bosch i_stream_set_name(conn->input, conn->name);
67e0afe62b26d222614b8d817155bf5c74bd7fe0Stephan Bosch
67e0afe62b26d222614b8d817155bf5c74bd7fe0Stephan Bosch conn->output = output;
67e0afe62b26d222614b8d817155bf5c74bd7fe0Stephan Bosch o_stream_ref(conn->output);
67e0afe62b26d222614b8d817155bf5c74bd7fe0Stephan Bosch o_stream_set_no_error_handling(conn->output, TRUE);
67e0afe62b26d222614b8d817155bf5c74bd7fe0Stephan Bosch o_stream_set_name(conn->output, conn->name);
67e0afe62b26d222614b8d817155bf5c74bd7fe0Stephan Bosch
c85f67cfb8e1cef2de2b681debf4703d5818dc01Stephan Bosch connection_input_resume(conn);
67e0afe62b26d222614b8d817155bf5c74bd7fe0Stephan Bosch
67e0afe62b26d222614b8d817155bf5c74bd7fe0Stephan Bosch if (list->v.client_connected != NULL)
67e0afe62b26d222614b8d817155bf5c74bd7fe0Stephan Bosch list->v.client_connected(conn, TRUE);
67e0afe62b26d222614b8d817155bf5c74bd7fe0Stephan Bosch}
67e0afe62b26d222614b8d817155bf5c74bd7fe0Stephan Bosch
6793538c389d3e725456e3eabb697e2743233646Stephan Boschstatic void connection_socket_connected(struct connection *conn)
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen{
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen io_remove(&conn->io);
0d1b8b6bec79746c5d89d57dd8c1688946bd9237Josef 'Jeff' Sipek timeout_remove(&conn->to);
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen
7db7fbea5d8a07463b625f93d69166d56018dadfTimo Sirainen errno = net_geterror(conn->fd_in);
7db7fbea5d8a07463b625f93d69166d56018dadfTimo Sirainen connection_client_connected(conn, errno == 0);
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen}
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainenint connection_client_connect(struct connection *conn)
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen{
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen const struct connection_settings *set = &conn->list->set;
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen int fd;
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen i_assert(conn->list->set.client);
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen i_assert(conn->fd_in == -1);
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen
54c6a8135c0ded324f7ae7d0cdf1ef177004ee2dStephan Bosch if (conn->port != 0) {
54c6a8135c0ded324f7ae7d0cdf1ef177004ee2dStephan Bosch fd = net_connect_ip(&conn->ip, conn->port,
54c6a8135c0ded324f7ae7d0cdf1ef177004ee2dStephan Bosch (conn->my_ip.family != 0 ? &conn->my_ip : NULL));
54c6a8135c0ded324f7ae7d0cdf1ef177004ee2dStephan Bosch } else if (conn->list->set.unix_client_connect_msecs == 0)
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen fd = net_connect_unix(conn->name);
4487c66123ca4830f8afbf4efcd7a260848d0e05Timo Sirainen else
4487c66123ca4830f8afbf4efcd7a260848d0e05Timo Sirainen fd = net_connect_unix_with_retries(conn->name, conn->list->set.unix_client_connect_msecs);
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen if (fd == -1)
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen return -1;
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen conn->fd_in = conn->fd_out = fd;
2c5c70e12365d7910848259f88eb237ce3a15947Timo Sirainen conn->connect_started = ioloop_timeval;
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen
cb3ab2fd5668700a89b274a43595cfbfa1616e4bTimo Sirainen if (conn->port != 0 ||
cb3ab2fd5668700a89b274a43595cfbfa1616e4bTimo Sirainen conn->list->set.delayed_unix_client_connected_callback) {
086b73efd1a5812a64acc951366a499d325509a6Stephan Bosch conn->io = io_add_to(conn->ioloop, conn->fd_out, IO_WRITE,
086b73efd1a5812a64acc951366a499d325509a6Stephan Bosch connection_socket_connected, conn);
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen if (set->client_connect_timeout_msecs != 0) {
086b73efd1a5812a64acc951366a499d325509a6Stephan Bosch conn->to = timeout_add_to(conn->ioloop,
086b73efd1a5812a64acc951366a499d325509a6Stephan Bosch set->client_connect_timeout_msecs,
086b73efd1a5812a64acc951366a499d325509a6Stephan Bosch connection_connect_timeout, conn);
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen }
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen } else {
7db7fbea5d8a07463b625f93d69166d56018dadfTimo Sirainen connection_client_connected(conn, TRUE);
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen }
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen return 0;
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen}
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainenvoid connection_disconnect(struct connection *conn)
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen{
a2d962e729a1c162145b86b3b6a666ef0a139e52Timo Sirainen conn->last_input = 0;
efe78d3ba24fc866af1c79b9223dc0809ba26cadStephan Bosch i_zero(&conn->last_input_tv);
0d1b8b6bec79746c5d89d57dd8c1688946bd9237Josef 'Jeff' Sipek timeout_remove(&conn->to);
5f1d689131a75c39f064cbd4202373e7edf78f18Josef 'Jeff' Sipek io_remove(&conn->io);
9a84b90d894a741ae6e090de104d31382a41d0aaJosef 'Jeff' Sipek i_stream_close(conn->input);
9a84b90d894a741ae6e090de104d31382a41d0aaJosef 'Jeff' Sipek i_stream_destroy(&conn->input);
9a84b90d894a741ae6e090de104d31382a41d0aaJosef 'Jeff' Sipek o_stream_close(conn->output);
9a84b90d894a741ae6e090de104d31382a41d0aaJosef 'Jeff' Sipek o_stream_destroy(&conn->output);
33a80622828063f5be6f743855d5273fabe8ae58Timo Sirainen fd_close_maybe_stdio(&conn->fd_in, &conn->fd_out);
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen}
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainenvoid connection_deinit(struct connection *conn)
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen{
a618726eb3eb09a3866fe93208baf923d593f4d3Timo Sirainen i_assert(conn->list->connections_count > 0);
a618726eb3eb09a3866fe93208baf923d593f4d3Timo Sirainen
a618726eb3eb09a3866fe93208baf923d593f4d3Timo Sirainen conn->list->connections_count--;
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen DLLIST_REMOVE(&conn->list->connections, conn);
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen connection_disconnect(conn);
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen i_free(conn->name);
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen}
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainenint connection_input_read(struct connection *conn)
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen{
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen conn->last_input = ioloop_time;
a238c6fede2022e5a4af707107ffb8f047b7753fTimo Sirainen conn->last_input_tv = ioloop_timeval;
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen if (conn->to != NULL)
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen timeout_reset(conn->to);
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen switch (i_stream_read(conn->input)) {
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen case -2:
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen /* buffer full */
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen switch (conn->list->set.input_full_behavior) {
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen case CONNECTION_BEHAVIOR_DESTROY:
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen conn->disconnect_reason =
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen CONNECTION_DISCONNECT_BUFFER_FULL;
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen conn->list->v.destroy(conn);
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen return -1;
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen case CONNECTION_BEHAVIOR_ALLOW:
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen return -2;
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen }
48325adac125d7ff275ec69b05b7a92be9637630Timo Sirainen i_unreached();
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen case -1:
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen /* disconnected */
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen conn->disconnect_reason =
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen CONNECTION_DISCONNECT_CONN_CLOSED;
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen conn->list->v.destroy(conn);
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen return -1;
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen case 0:
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen /* nothing new read */
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen return 0;
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen default:
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen /* something was read */
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen return 1;
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen }
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen}
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainenconst char *connection_disconnect_reason(struct connection *conn)
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen{
c61779cfa45c1684b1f7c462011088bad0b8318cTimo Sirainen switch (conn->disconnect_reason) {
c61779cfa45c1684b1f7c462011088bad0b8318cTimo Sirainen case CONNECTION_DISCONNECT_DEINIT:
c61779cfa45c1684b1f7c462011088bad0b8318cTimo Sirainen return "Deinitializing";
c61779cfa45c1684b1f7c462011088bad0b8318cTimo Sirainen case CONNECTION_DISCONNECT_CONNECT_TIMEOUT: {
c61779cfa45c1684b1f7c462011088bad0b8318cTimo Sirainen unsigned int msecs =
c61779cfa45c1684b1f7c462011088bad0b8318cTimo Sirainen conn->list->set.client_connect_timeout_msecs;
c61779cfa45c1684b1f7c462011088bad0b8318cTimo Sirainen return t_strdup_printf("connect() timed out in %u.%03u secs",
c61779cfa45c1684b1f7c462011088bad0b8318cTimo Sirainen msecs/1000, msecs%1000);
c61779cfa45c1684b1f7c462011088bad0b8318cTimo Sirainen }
c61779cfa45c1684b1f7c462011088bad0b8318cTimo Sirainen case CONNECTION_DISCONNECT_IDLE_TIMEOUT:
c61779cfa45c1684b1f7c462011088bad0b8318cTimo Sirainen return "Idle timeout";
c61779cfa45c1684b1f7c462011088bad0b8318cTimo Sirainen case CONNECTION_DISCONNECT_CONN_CLOSED:
c61779cfa45c1684b1f7c462011088bad0b8318cTimo Sirainen if (conn->input == NULL)
c61779cfa45c1684b1f7c462011088bad0b8318cTimo Sirainen return t_strdup_printf("connect() failed: %m");
c61779cfa45c1684b1f7c462011088bad0b8318cTimo Sirainen /* fall through */
c61779cfa45c1684b1f7c462011088bad0b8318cTimo Sirainen case CONNECTION_DISCONNECT_NOT:
c61779cfa45c1684b1f7c462011088bad0b8318cTimo Sirainen case CONNECTION_DISCONNECT_BUFFER_FULL:
c61779cfa45c1684b1f7c462011088bad0b8318cTimo Sirainen return io_stream_get_disconnect_reason(conn->input, conn->output);
c61779cfa45c1684b1f7c462011088bad0b8318cTimo Sirainen }
c61779cfa45c1684b1f7c462011088bad0b8318cTimo Sirainen i_unreached();
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen}
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen
d951320d498ae0800b677b754dde71574102123bTimo Sirainenconst char *connection_input_timeout_reason(struct connection *conn)
d951320d498ae0800b677b754dde71574102123bTimo Sirainen{
d951320d498ae0800b677b754dde71574102123bTimo Sirainen if (conn->last_input_tv.tv_sec != 0) {
d951320d498ae0800b677b754dde71574102123bTimo Sirainen int diff = timeval_diff_msecs(&ioloop_timeval, &conn->last_input_tv);
d951320d498ae0800b677b754dde71574102123bTimo Sirainen return t_strdup_printf("No input for %u.%03u secs",
d951320d498ae0800b677b754dde71574102123bTimo Sirainen diff/1000, diff%1000);
d951320d498ae0800b677b754dde71574102123bTimo Sirainen } else if (conn->connect_finished.tv_sec != 0) {
d951320d498ae0800b677b754dde71574102123bTimo Sirainen int diff = timeval_diff_msecs(&ioloop_timeval, &conn->connect_finished);
d951320d498ae0800b677b754dde71574102123bTimo Sirainen return t_strdup_printf(
d951320d498ae0800b677b754dde71574102123bTimo Sirainen "No input since connected %u.%03u secs ago",
d951320d498ae0800b677b754dde71574102123bTimo Sirainen diff/1000, diff%1000);
d951320d498ae0800b677b754dde71574102123bTimo Sirainen } else {
d951320d498ae0800b677b754dde71574102123bTimo Sirainen int diff = timeval_diff_msecs(&ioloop_timeval, &conn->connect_started);
d951320d498ae0800b677b754dde71574102123bTimo Sirainen return t_strdup_printf("connect() timed out after %u.%03u secs",
d951320d498ae0800b677b754dde71574102123bTimo Sirainen diff/1000, diff%1000);
d951320d498ae0800b677b754dde71574102123bTimo Sirainen }
d951320d498ae0800b677b754dde71574102123bTimo Sirainen}
d951320d498ae0800b677b754dde71574102123bTimo Sirainen
ddaf416216a83e71bc1bfc1b6faf2ead9d774613Stephan Boschvoid connection_switch_ioloop_to(struct connection *conn,
ddaf416216a83e71bc1bfc1b6faf2ead9d774613Stephan Bosch struct ioloop *ioloop)
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen{
086b73efd1a5812a64acc951366a499d325509a6Stephan Bosch conn->ioloop = ioloop;
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen if (conn->io != NULL)
ddaf416216a83e71bc1bfc1b6faf2ead9d774613Stephan Bosch conn->io = io_loop_move_io_to(ioloop, &conn->io);
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen if (conn->to != NULL)
ddaf416216a83e71bc1bfc1b6faf2ead9d774613Stephan Bosch conn->to = io_loop_move_timeout_to(ioloop, &conn->to);
959eca738ab09d2760fd96ba329263fe589f84b0Timo Sirainen if (conn->input != NULL)
ddaf416216a83e71bc1bfc1b6faf2ead9d774613Stephan Bosch i_stream_switch_ioloop_to(conn->input, ioloop);
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen if (conn->output != NULL)
ddaf416216a83e71bc1bfc1b6faf2ead9d774613Stephan Bosch o_stream_switch_ioloop_to(conn->output, ioloop);
ddaf416216a83e71bc1bfc1b6faf2ead9d774613Stephan Bosch}
ddaf416216a83e71bc1bfc1b6faf2ead9d774613Stephan Bosch
ddaf416216a83e71bc1bfc1b6faf2ead9d774613Stephan Boschvoid connection_switch_ioloop(struct connection *conn)
ddaf416216a83e71bc1bfc1b6faf2ead9d774613Stephan Bosch{
ddaf416216a83e71bc1bfc1b6faf2ead9d774613Stephan Bosch connection_switch_ioloop_to(conn, current_ioloop);
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen}
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainenstruct connection_list *
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainenconnection_list_init(const struct connection_settings *set,
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen const struct connection_vfuncs *vfuncs)
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen{
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen struct connection_list *list;
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen i_assert(vfuncs->input != NULL ||
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen set->input_full_behavior != CONNECTION_BEHAVIOR_ALLOW);
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen i_assert(set->major_version == 0 ||
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen (set->service_name_in != NULL &&
3e675de58a30e18fc973d4f0203ed3a4175c8ac5Aki Tuomi set->service_name_out != NULL &&
3e675de58a30e18fc973d4f0203ed3a4175c8ac5Aki Tuomi set->output_max_size != 0));
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen list = i_new(struct connection_list, 1);
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen list->set = *set;
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen list->v = *vfuncs;
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen if (list->v.input == NULL)
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen list->v.input = connection_input_default;
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen if (list->v.input_line == NULL)
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen list->v.input_line = connection_input_line_default;
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen return list;
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen}
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainenvoid connection_list_deinit(struct connection_list **_list)
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen{
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen struct connection_list *list = *_list;
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen struct connection *conn;
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen *_list = NULL;
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen while (list->connections != NULL) {
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen conn = list->connections;
00b706a9ea136a5945f4ebafaa4ba958b641635dTimo Sirainen conn->disconnect_reason = CONNECTION_DISCONNECT_DEINIT;
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen list->v.destroy(conn);
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen i_assert(conn != list->connections);
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen }
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen i_free(list);
96f89d51e8315f644f46804a9f0fc4f685ac48bfTimo Sirainen}