connection.c revision c85f67cfb8e1cef2de2b681debf4703d5818dc01
45312f52ff3a3d4c137447be4c7556500c2f8bf2Timo Sirainen/* Copyright (c) 2013-2018 Dovecot authors, see the included COPYING file */
df02611c44e9432e7961223bf9bfa3fb233b1789Timo Sirainenstatic void connection_idle_timeout(struct connection *conn)
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen conn->disconnect_reason = CONNECTION_DISCONNECT_IDLE_TIMEOUT;
df02611c44e9432e7961223bf9bfa3fb233b1789Timo Sirainenstatic void connection_connect_timeout(struct connection *conn)
cb1fd563e6000153d1be76fd8722a096bd144b77Timo Sirainen conn->disconnect_reason = CONNECTION_DISCONNECT_CONNECT_TIMEOUT;
3320f4770d1f6c2cdd10f3c4ca5a324beb335339Timo Sirainenvoid connection_input_default(struct connection *conn)
cb1fd563e6000153d1be76fd8722a096bd144b77Timo Sirainen case 0: /* allow calling this function for buffered input */
cb1fd563e6000153d1be76fd8722a096bd144b77Timo Sirainen while (!input->closed && (line = i_stream_next_line(input)) != NULL) {
cb1fd563e6000153d1be76fd8722a096bd144b77Timo Sirainen conn->disconnect_reason = CONNECTION_DISCONNECT_DEINIT;
3320f4770d1f6c2cdd10f3c4ca5a324beb335339Timo Sirainenint connection_verify_version(struct connection *conn,
cb1fd563e6000153d1be76fd8722a096bd144b77Timo Sirainen const char *const *args)
cb1fd563e6000153d1be76fd8722a096bd144b77Timo Sirainen /* VERSION <tab> service_name <tab> major version <tab> minor version */
cb1fd563e6000153d1be76fd8722a096bd144b77Timo Sirainen str_to_uint(args[2], &recv_major_version) < 0 ||
cb1fd563e6000153d1be76fd8722a096bd144b77Timo Sirainen str_to_uint(args[3], &conn->minor_version) < 0) {
b58fbcc79c40f867eccae98548fcd25a16823433Timo Sirainen i_error("%s didn't reply with a valid VERSION line: %s",
b58fbcc79c40f867eccae98548fcd25a16823433Timo Sirainen if (strcmp(args[1], conn->list->set.service_name_in) != 0) {
cb1fd563e6000153d1be76fd8722a096bd144b77Timo Sirainen i_error("%s: Connected to wrong socket type. "
b58fbcc79c40f867eccae98548fcd25a16823433Timo Sirainen "We want '%s', but received '%s'", conn->name,
cb1fd563e6000153d1be76fd8722a096bd144b77Timo Sirainen if (recv_major_version != conn->list->set.major_version) {
cb1fd563e6000153d1be76fd8722a096bd144b77Timo Sirainen i_error("%s: Socket supports major version %u, "
cb1fd563e6000153d1be76fd8722a096bd144b77Timo Sirainen "but we support only %u (mixed old and new binaries?)",
cb1fd563e6000153d1be76fd8722a096bd144b77Timo Sirainenint connection_input_line_default(struct connection *conn, const char *line)
cb1fd563e6000153d1be76fd8722a096bd144b77Timo Sirainen const char *const *args;
cb1fd563e6000153d1be76fd8722a096bd144b77Timo Sirainen if (connection_verify_version(conn, args) < 0)
cb1fd563e6000153d1be76fd8722a096bd144b77Timo Sirainen if (args[0] == NULL && !conn->list->set.allow_empty_args_input) {
b58fbcc79c40f867eccae98548fcd25a16823433Timo Sirainen i_error("%s: Unexpectedly received empty line", conn->name);
b58fbcc79c40f867eccae98548fcd25a16823433Timo Sirainenvoid connection_input_halt(struct connection *conn)
cb1fd563e6000153d1be76fd8722a096bd144b77Timo Sirainenvoid connection_input_resume(struct connection *conn)
b58fbcc79c40f867eccae98548fcd25a16823433Timo Sirainen const struct connection_settings *set = &conn->list->set;
cb1fd563e6000153d1be76fd8722a096bd144b77Timo Sirainen if (conn->from_streams || set->input_max_size != 0) {
b58fbcc79c40f867eccae98548fcd25a16823433Timo Sirainen conn->io = io_add_istream_to(conn->ioloop, conn->input,
b58fbcc79c40f867eccae98548fcd25a16823433Timo Sirainen conn->io = io_add_to(conn->ioloop, conn->fd_in, IO_READ,
cb1fd563e6000153d1be76fd8722a096bd144b77Timo Sirainenstatic void connection_init_streams(struct connection *conn)
cb1fd563e6000153d1be76fd8722a096bd144b77Timo Sirainen const struct connection_settings *set = &conn->list->set;
b58fbcc79c40f867eccae98548fcd25a16823433Timo Sirainen conn->version_received = set->major_version == 0;
b58fbcc79c40f867eccae98548fcd25a16823433Timo Sirainen conn->input = i_stream_create_unix(conn->fd_in,
b58fbcc79c40f867eccae98548fcd25a16823433Timo Sirainen conn->output = o_stream_create_unix(conn->fd_out,
cb1fd563e6000153d1be76fd8722a096bd144b77Timo Sirainen conn->output = o_stream_create_fd(conn->fd_out,
b58fbcc79c40f867eccae98548fcd25a16823433Timo Sirainen o_stream_set_no_error_handling(conn->output, TRUE);
cb1fd563e6000153d1be76fd8722a096bd144b77Timo Sirainen o_stream_set_finish_via_child(conn->output, FALSE);
b58fbcc79c40f867eccae98548fcd25a16823433Timo Sirainen i_stream_switch_ioloop_to(conn->input, conn->ioloop);
b58fbcc79c40f867eccae98548fcd25a16823433Timo Sirainen o_stream_switch_ioloop_to(conn->output, conn->ioloop);
df02611c44e9432e7961223bf9bfa3fb233b1789Timo Sirainen if (set->major_version != 0 && !set->dont_send_version) {
b58fbcc79c40f867eccae98548fcd25a16823433Timo Sirainen o_stream_nsend_str(conn->output, t_strdup_printf(
b58fbcc79c40f867eccae98548fcd25a16823433Timo Sirainen "VERSION\t%s\t%u\t%u\n", set->service_name_out,
b58fbcc79c40f867eccae98548fcd25a16823433Timo Sirainenvoid connection_streams_changed(struct connection *conn)
cb1fd563e6000153d1be76fd8722a096bd144b77Timo Sirainen const struct connection_settings *set = &conn->list->set;
b58fbcc79c40f867eccae98548fcd25a16823433Timo Sirainen if (set->input_max_size != 0 && conn->io != NULL) {
b58fbcc79c40f867eccae98548fcd25a16823433Timo Sirainenstatic void connection_client_connected(struct connection *conn, bool success)
b58fbcc79c40f867eccae98548fcd25a16823433Timo Sirainen conn->list->v.client_connected(conn, success);
b58fbcc79c40f867eccae98548fcd25a16823433Timo Sirainenvoid connection_init(struct connection_list *list,
b58fbcc79c40f867eccae98548fcd25a16823433Timo Sirainenvoid connection_init_server(struct connection_list *list,
b58fbcc79c40f867eccae98548fcd25a16823433Timo Sirainenvoid connection_init_client_ip(struct connection_list *list,
b58fbcc79c40f867eccae98548fcd25a16823433Timo Sirainen conn->name = i_strdup_printf("%s:%u", net_ip2addr(ip), port);
b58fbcc79c40f867eccae98548fcd25a16823433Timo Sirainenvoid connection_init_client_unix(struct connection_list *list,
b58fbcc79c40f867eccae98548fcd25a16823433Timo Sirainenvoid connection_init_from_streams(struct connection_list *list,
df02611c44e9432e7961223bf9bfa3fb233b1789Timo Sirainen struct istream *input, struct ostream *output)
b58fbcc79c40f867eccae98548fcd25a16823433Timo Sirainen o_stream_set_no_error_handling(conn->output, TRUE);
b58fbcc79c40f867eccae98548fcd25a16823433Timo Sirainenstatic void connection_socket_connected(struct connection *conn)
b58fbcc79c40f867eccae98548fcd25a16823433Timo Sirainen connection_client_connected(conn, errno == 0);
b58fbcc79c40f867eccae98548fcd25a16823433Timo Sirainenint connection_client_connect(struct connection *conn)
b58fbcc79c40f867eccae98548fcd25a16823433Timo Sirainen const struct connection_settings *set = &conn->list->set;
b58fbcc79c40f867eccae98548fcd25a16823433Timo Sirainen fd = net_connect_ip(&conn->ip, conn->port, NULL);
b58fbcc79c40f867eccae98548fcd25a16823433Timo Sirainen else if (conn->list->set.unix_client_connect_msecs == 0)
b58fbcc79c40f867eccae98548fcd25a16823433Timo Sirainen fd = net_connect_unix_with_retries(conn->name, conn->list->set.unix_client_connect_msecs);
1f6c210c30992e95b806d2f517e2b3625ed941c5Timo Sirainen conn->list->set.delayed_unix_client_connected_callback) {
b58fbcc79c40f867eccae98548fcd25a16823433Timo Sirainen conn->io = io_add_to(conn->ioloop, conn->fd_out, IO_WRITE,
b58fbcc79c40f867eccae98548fcd25a16823433Timo Sirainenvoid connection_disconnect(struct connection *conn)
b58fbcc79c40f867eccae98548fcd25a16823433Timo Sirainen fd_close_maybe_stdio(&conn->fd_in, &conn->fd_out);
b58fbcc79c40f867eccae98548fcd25a16823433Timo Sirainenvoid connection_deinit(struct connection *conn)
b58fbcc79c40f867eccae98548fcd25a16823433Timo Sirainen DLLIST_REMOVE(&conn->list->connections, conn);
b58fbcc79c40f867eccae98548fcd25a16823433Timo Sirainenint connection_input_read(struct connection *conn)
df02611c44e9432e7961223bf9bfa3fb233b1789Timo Sirainen /* buffer full */
b58fbcc79c40f867eccae98548fcd25a16823433Timo Sirainen switch (conn->list->set.input_full_behavior) {
82b990b0bb2a1dad5c2634a508a5ad87715db402Timo Sirainen /* disconnected */
82b990b0bb2a1dad5c2634a508a5ad87715db402Timo Sirainen /* nothing new read */
b58fbcc79c40f867eccae98548fcd25a16823433Timo Sirainen /* something was read */
b58fbcc79c40f867eccae98548fcd25a16823433Timo Sirainenconst char *connection_disconnect_reason(struct connection *conn)
b58fbcc79c40f867eccae98548fcd25a16823433Timo Sirainen return "Deinitializing";
b58fbcc79c40f867eccae98548fcd25a16823433Timo Sirainen unsigned int msecs =
b58fbcc79c40f867eccae98548fcd25a16823433Timo Sirainen return t_strdup_printf("connect() timed out in %u.%03u secs",
df02611c44e9432e7961223bf9bfa3fb233b1789Timo Sirainen return "Idle timeout";
b58fbcc79c40f867eccae98548fcd25a16823433Timo Sirainen return t_strdup_printf("connect() failed: %m");
df02611c44e9432e7961223bf9bfa3fb233b1789Timo Sirainen /* fall through */
df02611c44e9432e7961223bf9bfa3fb233b1789Timo Sirainen return io_stream_get_disconnect_reason(conn->input, conn->output);
return t_strdup_printf(
struct connection_list *
return list;