{
/* not enabled */
if (conn->list->set.output_throttle_size != 0 &&
- conn->output != NULL &&
+ !conn->output->closed &&
o_stream_get_buffer_used_size(conn->output) >=
conn->list->set.output_throttle_size) {
conn->flush_callback =
if (conn->io != NULL) {
/* do nothing */
- } else if (conn->input != NULL) {
+ } else if (conn->input != NULL && !conn->input->closed) {
conn->io = io_add_istream_to(conn->ioloop, conn->input,
*conn->v.input, conn);
if (set_io_pending)
{
const struct connection_settings *set = &conn->list->set;
+ /* If we're reconnecting, the iostreams still exist */
+ if (conn->input != NULL) {
+ i_assert(conn->input->closed);
+ i_stream_destroy(&conn->input);
+ }
+ if (conn->output != NULL) {
+ i_assert(conn->output->closed);
+ o_stream_destroy(&conn->output);
+ }
+
i_assert(conn->io == NULL);
- i_assert(conn->input == NULL);
- i_assert(conn->output == NULL);
i_assert(conn->to == NULL);
i_zero(&conn->handshake_finished);
if (list->set.debug)
event_set_forced_debug(conn->event, TRUE);
+ /* Use error iostreams until the client is connected.
+ This way caller can rely on them always being non-NULL. */
+ const char *conn_error = "connect() not finished yet";
+ if (list->set.client && conn->input == NULL) {
+ conn->input = i_stream_create_error_str(EINPROGRESS, "%s",
+ conn_error);
+ }
+ if (list->set.client && conn->output == NULL) {
+ conn->output = o_stream_create_error_str(EINPROGRESS, "%s",
+ conn_error);
+ }
+
if (conn->list != NULL) {
i_assert(conn->list == list);
} else {
i_assert(conn->fd_in >= 0);
i_assert(conn->fd_out >= 0);
i_assert(conn->io == NULL);
- i_assert(conn->input == NULL);
- i_assert(conn->output == NULL);
i_assert(conn->to == NULL);
+ i_stream_destroy(&conn->input);
conn->input = input;
i_stream_ref(conn->input);
+ o_stream_destroy(&conn->output);
conn->output = output;
o_stream_ref(conn->output);
o_stream_set_no_error_handling(conn->output, TRUE);
conn->v.client_connected(conn, TRUE);
}
+static void connection_set_connect_error_streams(struct connection *conn)
+{
+ int stream_errno = errno;
+ const char *error = t_strdup_printf("connect(%s) failed: %m",
+ conn->name);
+ i_stream_destroy(&conn->input);
+ o_stream_destroy(&conn->output);
+ conn->input = i_stream_create_error_str(stream_errno, "%s", error);
+ conn->output = o_stream_create_error_str(stream_errno, "%s", error);
+ errno = stream_errno;
+}
+
static void connection_socket_connected(struct connection *conn)
{
io_remove(&conn->io);
timeout_remove(&conn->to);
errno = net_geterror(conn->fd_in);
+ if (errno != 0)
+ connection_set_connect_error_streams(conn);
connection_client_connected(conn, errno == 0);
}
} else {
fd = net_connect_unix_with_retries(conn->base_name, msecs);
}
- if (fd == -1)
+ if (fd == -1) {
+ connection_set_connect_error_streams(conn);
return -1;
+ }
conn->fd_in = conn->fd_out = fd;
conn->connect_started = ioloop_timeval;
conn->disconnected = FALSE;
timeout_remove(&conn->to);
io_remove(&conn->io);
i_stream_close(conn->input);
- i_stream_destroy(&conn->input);
o_stream_close(conn->output);
- o_stream_destroy(&conn->output);
if (conn->fd_in == conn->fd_out)
(void)shutdown(conn->fd_out, SHUT_RDWR);
fd_close_maybe_stdio(&conn->fd_in, &conn->fd_out);
DLLIST_REMOVE(&conn->list->connections, conn);
connection_disconnect(conn);
+ i_stream_destroy(&conn->input);
+ o_stream_destroy(&conn->output);
i_free(conn->base_name);
i_free(conn->label);
i_free(conn->property_label);
case CONNECTION_DISCONNECT_IDLE_TIMEOUT:
return "Idle timeout";
case CONNECTION_DISCONNECT_CONN_CLOSED:
- if (conn->input == NULL)
- return t_strdup_printf("connect(%s) failed: %m",
- conn->name);
+ if (!conn->client_connect_succeeded) {
+ /* connect() error is in the error istream */
+ return i_stream_get_error(conn->input);
+ }
/* fall through */
case CONNECTION_DISCONNECT_NOT:
case CONNECTION_DISCONNECT_BUFFER_FULL: