connection.c revision a327d9301f593433c228c4cc8cca05c95b37f6fb
45312f52ff3a3d4c137447be4c7556500c2f8bf2Timo Sirainen/* Copyright (c) 2012 Dovecot authors, see the included COPYING file */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "lib.h"
2d49f150b4bce6f2f59a84e268e4777901c3e42cTimo Sirainen#include "ioloop.h"
16f816d3f3c32ae3351834253f52ddd0212bcbf3Timo Sirainen#include "istream.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "ostream.h"
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen#include "network.h"
ffd9a1898a18fadfc5dce399162c25d50548f905Timo Sirainen#include "strescape.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "llist.h"
89b548af722113acb5d63dfffb44423cb60f91e4Timo Sirainen#include "connection.h"
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include <unistd.h>
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
66ae183b6e895216037bd921367670f4b0665911Timo Sirainenstatic void connection_idle_timeout(struct connection *conn)
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen{
a2f250a332dfc1e6cd4ffd196c621eb9dbf7b8a1Timo Sirainen conn->disconnect_reason = CONNECTION_DISCONNECT_IDLE_TIMEOUT;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen conn->list->v.destroy(conn);
da5d50534cfca45d0aaaf0bdac17b287b4588809Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic void connection_connect_timeout(struct connection *conn)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen conn->disconnect_reason = CONNECTION_DISCONNECT_CONNECT_TIMEOUT;
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen conn->list->v.destroy(conn);
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen}
46c31f64b9f0949f00b7819f45b22f2d64b2ea27Timo Sirainen
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainenvoid connection_input_default(struct connection *conn)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen const char *line;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct istream *input;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen int ret = 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen switch (connection_input_read(conn)) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen case -1:
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen case 0:
024815ea2ffdda9ea79919f18e865663977f73eaTimo Sirainen return;
8fa41238067c854435884c459963fde6f8c6436bTimo Sirainen case 1:
8fa41238067c854435884c459963fde6f8c6436bTimo Sirainen break;
91dca97b367c54a139c268b56a0c67f564bd9197Timo Sirainen default:
91dca97b367c54a139c268b56a0c67f564bd9197Timo Sirainen i_unreached();
46c31f64b9f0949f00b7819f45b22f2d64b2ea27Timo Sirainen }
46c31f64b9f0949f00b7819f45b22f2d64b2ea27Timo Sirainen
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen input = conn->input;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_stream_ref(input);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen while (!input->closed && (line = i_stream_next_line(input)) != NULL) {
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen T_BEGIN {
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen ret = conn->list->v.input_line(conn, line);
5aeb15e5817fbd4b1d8de540aa7673e3819a8030Timo Sirainen } T_END;
5aeb15e5817fbd4b1d8de540aa7673e3819a8030Timo Sirainen if (ret <= 0)
41e1c7380edda701719d8ce1fb4d465d2ec4c84dTimo Sirainen break;
91dca97b367c54a139c268b56a0c67f564bd9197Timo Sirainen }
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen if (ret < 0 && !input->closed) {
3ccab0bac68040f179a7de45c516cec258e28fdbTimo Sirainen conn->disconnect_reason = CONNECTION_DISCONNECT_DEINIT;
3ccab0bac68040f179a7de45c516cec258e28fdbTimo Sirainen conn->list->v.destroy(conn);
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen }
a2f250a332dfc1e6cd4ffd196c621eb9dbf7b8a1Timo Sirainen i_stream_unref(&input);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenint connection_verify_version(struct connection *conn,
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen const char *const *args)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen unsigned int recv_major_version;
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen /* VERSION <tab> service_name <tab> major version <tab> minor version */
ee246b46953e4b94b2f22e093373674fa9155500Timo Sirainen if (str_array_length(args) != 4 ||
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen strcmp(args[0], "VERSION") != 0 ||
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen str_to_uint(args[2], &recv_major_version) < 0 ||
3ccab0bac68040f179a7de45c516cec258e28fdbTimo Sirainen str_to_uint(args[3], &conn->minor_version) < 0) {
648d24583c1574441c4fa0331a90bd4d6e7996c5Timo Sirainen i_error("%s didn't reply with a valid VERSION line",
648d24583c1574441c4fa0331a90bd4d6e7996c5Timo Sirainen conn->name);
ee246b46953e4b94b2f22e093373674fa9155500Timo Sirainen return -1;
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainen }
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
46c31f64b9f0949f00b7819f45b22f2d64b2ea27Timo Sirainen if (strcmp(args[1], conn->list->set.service_name_in) != 0) {
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen i_error("%s: Connected to wrong socket type. "
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen "We want '%s', but received '%s'", conn->name,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen conn->list->set.service_name_in, args[1]);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return -1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (recv_major_version != conn->list->set.major_version) {
80fc743146da5130de34174cdaad2576f103723fTimo Sirainen i_error("%s: Socket supports major version %u, "
80fc743146da5130de34174cdaad2576f103723fTimo Sirainen "but we support only %u (mixed old and new binaries?)",
80fc743146da5130de34174cdaad2576f103723fTimo Sirainen conn->name, recv_major_version,
80fc743146da5130de34174cdaad2576f103723fTimo Sirainen conn->list->set.major_version);
80fc743146da5130de34174cdaad2576f103723fTimo Sirainen return -1;
80fc743146da5130de34174cdaad2576f103723fTimo Sirainen }
20a802016205bbcafc90f164f769ea801f88d014Timo Sirainen return 0;
20a802016205bbcafc90f164f769ea801f88d014Timo Sirainen}
20a802016205bbcafc90f164f769ea801f88d014Timo Sirainen
20a802016205bbcafc90f164f769ea801f88d014Timo Sirainenint connection_input_line_default(struct connection *conn, const char *line)
20a802016205bbcafc90f164f769ea801f88d014Timo Sirainen{
20a802016205bbcafc90f164f769ea801f88d014Timo Sirainen const char *const *args;
20a802016205bbcafc90f164f769ea801f88d014Timo Sirainen
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen args = t_strsplit_tabescaped(line);
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen if (!conn->version_received) {
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen if (connection_verify_version(conn, args) < 0)
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen return -1;
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainen conn->version_received = TRUE;
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen return 1;
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen }
024815ea2ffdda9ea79919f18e865663977f73eaTimo Sirainen
d161e3c2cde2bd8d5917840f68823a2259ed426eTimo Sirainen return conn->list->v.input_args(conn, args);
ffd9a1898a18fadfc5dce399162c25d50548f905Timo Sirainen}
ffd9a1898a18fadfc5dce399162c25d50548f905Timo Sirainen
1e923fcf497665fe071a154c31fb452766b0b2deTimo Sirainenstatic void connection_init_streams(struct connection *conn)
d161e3c2cde2bd8d5917840f68823a2259ed426eTimo Sirainen{
1e923fcf497665fe071a154c31fb452766b0b2deTimo Sirainen const struct connection_settings *set = &conn->list->set;
d161e3c2cde2bd8d5917840f68823a2259ed426eTimo Sirainen
d161e3c2cde2bd8d5917840f68823a2259ed426eTimo Sirainen i_assert(conn->io == NULL);
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen i_assert(conn->input == NULL);
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen i_assert(conn->output == NULL);
1175f27441385a7011629f295f42708f9a3a4ffcTimo Sirainen i_assert(conn->to == NULL);
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen conn->version_received = set->major_version == 0;
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen if (set->input_max_size != 0) {
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen conn->input = i_stream_create_fd(conn->fd_in,
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen set->input_max_size, FALSE);
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen }
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen if (set->output_max_size != 0) {
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen conn->output = o_stream_create_fd(conn->fd_out,
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen set->output_max_size, FALSE);
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen o_stream_set_no_error_handling(conn->output, TRUE);
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen }
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen conn->io = io_add(conn->fd_in, IO_READ, conn->list->v.input, conn);
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen if (set->input_idle_timeout_secs != 0) {
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen conn->to = timeout_add(set->input_idle_timeout_secs*1000,
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen connection_idle_timeout, conn);
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen }
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen if (set->major_version != 0 && !set->dont_send_version) {
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen o_stream_nsend_str(conn->output, t_strdup_printf(
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen "VERSION\t%s\t%u\t%u\n", set->service_name_out,
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen set->major_version, set->minor_version));
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen }
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen if (conn->list->v.connected != NULL)
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen conn->list->v.connected(conn);
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen}
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainenvoid connection_init_server(struct connection_list *list,
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen struct connection *conn, const char *name,
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen int fd_in, int fd_out)
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen{
59151b71059df1190acd75d8717ed04a7920c862Timo Sirainen i_assert(name != NULL);
da985034a708db2f61394b30d117050ae6829ee5Timo Sirainen i_assert(!list->set.client);
59151b71059df1190acd75d8717ed04a7920c862Timo Sirainen
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen conn->list = list;
de12ff295bb3d0873b4dced5840612cbacd635efTimo Sirainen conn->name = i_strdup(name);
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen conn->fd_in = fd_in;
8d80659e504ffb34bb0c6a633184fece35751b18Timo Sirainen conn->fd_out = fd_out;
7d7b5c98f086ffa8ac9c90f21db17748ca607202Timo Sirainen connection_init_streams(conn);
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen
de12ff295bb3d0873b4dced5840612cbacd635efTimo Sirainen DLLIST_PREPEND(&list->connections, conn);
da985034a708db2f61394b30d117050ae6829ee5Timo Sirainen}
da985034a708db2f61394b30d117050ae6829ee5Timo Sirainen
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainenvoid connection_init_client_ip(struct connection_list *list,
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen struct connection *conn,
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen const struct ip_addr *ip, unsigned int port)
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen{
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen i_assert(list->set.client);
de12ff295bb3d0873b4dced5840612cbacd635efTimo Sirainen
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen conn->fd_in = conn->fd_out = -1;
8d80659e504ffb34bb0c6a633184fece35751b18Timo Sirainen conn->list = list;
de12ff295bb3d0873b4dced5840612cbacd635efTimo Sirainen conn->name = i_strdup_printf("%s:%u", net_ip2addr(ip), port);
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen
de12ff295bb3d0873b4dced5840612cbacd635efTimo Sirainen conn->ip = *ip;
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen conn->port = port;
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen DLLIST_PREPEND(&list->connections, conn);
5626ae5e3316eced244adb6485c0927f1c7fdc41Timo Sirainen}
5626ae5e3316eced244adb6485c0927f1c7fdc41Timo Sirainen
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainenvoid connection_init_client_unix(struct connection_list *list,
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen struct connection *conn, const char *path)
5626ae5e3316eced244adb6485c0927f1c7fdc41Timo Sirainen{
8d80659e504ffb34bb0c6a633184fece35751b18Timo Sirainen i_assert(list->set.client);
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen conn->fd_in = conn->fd_out = -1;
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen conn->list = list;
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen conn->name = i_strdup(path);
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen DLLIST_PREPEND(&list->connections, conn);
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen}
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainenstatic void connection_connected(struct connection *conn)
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen{
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen io_remove(&conn->io);
8d80659e504ffb34bb0c6a633184fece35751b18Timo Sirainen if (conn->to != NULL)
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen timeout_remove(&conn->to);
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen connection_init_streams(conn);
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen}
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainenint connection_client_connect(struct connection *conn)
f23298fea47eecbeded985ee2537a34c4c4ef56bTimo Sirainen{
f23298fea47eecbeded985ee2537a34c4c4ef56bTimo Sirainen const struct connection_settings *set = &conn->list->set;
f23298fea47eecbeded985ee2537a34c4c4ef56bTimo Sirainen int fd;
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainen
f23298fea47eecbeded985ee2537a34c4c4ef56bTimo Sirainen i_assert(conn->list->set.client);
f23298fea47eecbeded985ee2537a34c4c4ef56bTimo Sirainen i_assert(conn->fd_in == -1);
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen if (conn->port != 0)
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen fd = net_connect_ip(&conn->ip, conn->port, NULL);
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen else
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen fd = net_connect_unix(conn->name);
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen if (fd == -1)
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen return -1;
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen conn->fd_in = conn->fd_out = fd;
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen if (conn->port != 0) {
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen conn->io = io_add(conn->fd_out, IO_WRITE,
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen connection_connected, conn);
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen if (set->client_connect_timeout_msecs != 0) {
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen conn->to = timeout_add(set->client_connect_timeout_msecs,
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen connection_connect_timeout, conn);
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen }
6825360d446542046757b06064282301c4c6b27cTimo Sirainen } else {
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen connection_init_streams(conn);
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen }
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen return 0;
6a04c5112961c5f4fb2d2f25192b3dc424d62ad0Timo Sirainen}
6a04c5112961c5f4fb2d2f25192b3dc424d62ad0Timo Sirainen
6a04c5112961c5f4fb2d2f25192b3dc424d62ad0Timo Sirainenvoid connection_disconnect(struct connection *conn)
3ccab0bac68040f179a7de45c516cec258e28fdbTimo Sirainen{
3ccab0bac68040f179a7de45c516cec258e28fdbTimo Sirainen if (conn->to != NULL)
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen timeout_remove(&conn->to);
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen if (conn->io != NULL)
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen io_remove(&conn->io);
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen if (conn->input != NULL)
6825360d446542046757b06064282301c4c6b27cTimo Sirainen i_stream_destroy(&conn->input);
6825360d446542046757b06064282301c4c6b27cTimo Sirainen if (conn->output != NULL)
6825360d446542046757b06064282301c4c6b27cTimo Sirainen o_stream_destroy(&conn->output);
6825360d446542046757b06064282301c4c6b27cTimo Sirainen if (conn->fd_in != -1) {
6825360d446542046757b06064282301c4c6b27cTimo Sirainen if (close(conn->fd_in) < 0)
6825360d446542046757b06064282301c4c6b27cTimo Sirainen i_error("close(%s) failed: %m", conn->name);
6825360d446542046757b06064282301c4c6b27cTimo Sirainen if (conn->fd_in != conn->fd_out)
6825360d446542046757b06064282301c4c6b27cTimo Sirainen i_error("close(%s/out) failed: %m", conn->name);
6825360d446542046757b06064282301c4c6b27cTimo Sirainen conn->fd_in = conn->fd_out = -1;
6825360d446542046757b06064282301c4c6b27cTimo Sirainen }
c8d093d149253fe8faec267c5057f45fe626f84cTimo Sirainen}
c8d093d149253fe8faec267c5057f45fe626f84cTimo Sirainen
6825360d446542046757b06064282301c4c6b27cTimo Sirainenvoid connection_deinit(struct connection *conn)
6825360d446542046757b06064282301c4c6b27cTimo Sirainen{
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen DLLIST_REMOVE(&conn->list->connections, conn);
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen connection_disconnect(conn);
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen i_free(conn->name);
3ccab0bac68040f179a7de45c516cec258e28fdbTimo Sirainen}
3ccab0bac68040f179a7de45c516cec258e28fdbTimo Sirainen
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainenint connection_input_read(struct connection *conn)
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen{
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen conn->last_input = ioloop_time;
8d80659e504ffb34bb0c6a633184fece35751b18Timo Sirainen if (conn->to != NULL)
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen timeout_reset(conn->to);
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen switch (i_stream_read(conn->input)) {
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen case -2:
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen /* buffer full */
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen switch (conn->list->set.input_full_behavior) {
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen case CONNECTION_BEHAVIOR_DESTROY:
4b231ca0bbe3b536acbd350101e183441ce0247aTimo Sirainen conn->disconnect_reason =
4b231ca0bbe3b536acbd350101e183441ce0247aTimo Sirainen CONNECTION_DISCONNECT_BUFFER_FULL;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen conn->list->v.destroy(conn);
c53e8ee216904ffe6de4f6518d9f9f5107b7610eTimo Sirainen return -1;
c53e8ee216904ffe6de4f6518d9f9f5107b7610eTimo Sirainen case CONNECTION_BEHAVIOR_ALLOW:
c53e8ee216904ffe6de4f6518d9f9f5107b7610eTimo Sirainen return -2;
c53e8ee216904ffe6de4f6518d9f9f5107b7610eTimo Sirainen }
c53e8ee216904ffe6de4f6518d9f9f5107b7610eTimo Sirainen case -1:
c53e8ee216904ffe6de4f6518d9f9f5107b7610eTimo Sirainen /* disconnected */
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen conn->disconnect_reason =
1e47cfede3a0b62654105daab00e97b5d660bc6bTimo Sirainen CONNECTION_DISCONNECT_CONN_CLOSED;
1e47cfede3a0b62654105daab00e97b5d660bc6bTimo Sirainen conn->list->v.destroy(conn);
1e47cfede3a0b62654105daab00e97b5d660bc6bTimo Sirainen return -1;
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen case 0:
1e47cfede3a0b62654105daab00e97b5d660bc6bTimo Sirainen /* nothing new read */
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen return 0;
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen default:
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen /* something was read */
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen return 1;
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen }
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen}
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainenconst char *connection_disconnect_reason(struct connection *conn)
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen{
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen if (conn->input != NULL && conn->input->stream_errno != 0)
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen errno = conn->input->stream_errno;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen else if (conn->output != NULL && conn->output->stream_errno != 0)
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen errno = conn->output->stream_errno;
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen return errno == 0 || errno == EPIPE ? "Connection closed" :
1e47cfede3a0b62654105daab00e97b5d660bc6bTimo Sirainen t_strdup_printf("Connection closed: %m");
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen}
4b231ca0bbe3b536acbd350101e183441ce0247aTimo Sirainen
4b231ca0bbe3b536acbd350101e183441ce0247aTimo Sirainenvoid connection_switch_ioloop(struct connection *conn)
4b231ca0bbe3b536acbd350101e183441ce0247aTimo Sirainen{
3697080532ccd9f51fac108be6079b616c7a2ddfTimo Sirainen if (conn->io != NULL)
14c474d9f4591c397ed0b5206af6537c7b52c924Timo Sirainen conn->io = io_loop_move_io(&conn->io);
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen if (conn->to != NULL)
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen conn->to = io_loop_move_timeout(&conn->to);
e3689d0f073341e844638f34e1e4d0b7bb053cc8Timo Sirainen if (conn->output != NULL)
e3689d0f073341e844638f34e1e4d0b7bb053cc8Timo Sirainen o_stream_switch_ioloop(conn->output);
e3689d0f073341e844638f34e1e4d0b7bb053cc8Timo Sirainen}
e3689d0f073341e844638f34e1e4d0b7bb053cc8Timo Sirainen
e3689d0f073341e844638f34e1e4d0b7bb053cc8Timo Sirainenstruct connection_list *
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainenconnection_list_init(const struct connection_settings *set,
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen const struct connection_vfuncs *vfuncs)
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen{
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen struct connection_list *list;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_assert(vfuncs->input != NULL ||
d22390f33eedbd2413debabc0662dde5241b1aa6Timo Sirainen set->input_full_behavior != CONNECTION_BEHAVIOR_ALLOW);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_assert(set->major_version == 0 ||
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen (set->service_name_in != NULL &&
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen set->service_name_out != NULL));
4b231ca0bbe3b536acbd350101e183441ce0247aTimo Sirainen
4b231ca0bbe3b536acbd350101e183441ce0247aTimo Sirainen list = i_new(struct connection_list, 1);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen list->set = *set;
d22390f33eedbd2413debabc0662dde5241b1aa6Timo Sirainen list->v = *vfuncs;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
d22390f33eedbd2413debabc0662dde5241b1aa6Timo Sirainen if (list->v.input == NULL)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen list->v.input = connection_input_default;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (list->v.input_line == NULL)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen list->v.input_line = connection_input_line_default;
d22390f33eedbd2413debabc0662dde5241b1aa6Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return list;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenvoid connection_list_deinit(struct connection_list **_list)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct connection_list *list = *_list;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct connection *conn;
1fd0d511885c30028aba388588151acf4ee85e75Timo Sirainen
1fd0d511885c30028aba388588151acf4ee85e75Timo Sirainen *_list = NULL;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen while (list->connections != NULL) {
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen conn = list->connections;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen list->v.destroy(conn);
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen i_assert(conn != list->connections);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen i_free(list);
1fd0d511885c30028aba388588151acf4ee85e75Timo Sirainen}
4b231ca0bbe3b536acbd350101e183441ce0247aTimo Sirainen