summaryrefslogtreecommitdiffstats
path: root/src/lib/iostream.c
blob: f2ba00088d2465c0b235a81c786e375115c1b57f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
/* Copyright (c) 2002-2018 Dovecot authors, see the included COPYING file */

#include "lib.h"
#include "array.h"
#include "istream.h"
#include "ostream.h"
#include "iostream-private.h"

static void
io_stream_default_close(struct iostream_private *stream ATTR_UNUSED,
			bool close_parent ATTR_UNUSED)
{
}

static void
io_stream_default_destroy(struct iostream_private *stream ATTR_UNUSED)
{
}

void io_stream_init(struct iostream_private *stream)
{
	if (stream->close == NULL)
		stream->close = io_stream_default_close;
	if (stream->destroy == NULL)
		stream->destroy = io_stream_default_destroy;
	stream->ioloop = current_ioloop;

	stream->refcount = 1;
}

void io_stream_ref(struct iostream_private *stream)
{
	i_assert(stream->refcount > 0);

	stream->refcount++;
}

bool io_stream_unref(struct iostream_private *stream)
{
	i_assert(stream->refcount > 0);
	if (--stream->refcount != 0)
		return TRUE;

	stream->close(stream, FALSE);
	stream->destroy(stream);
	return FALSE;
}

void io_stream_free(struct iostream_private *stream)
{
	const struct iostream_destroy_callback *dc;

	if (array_is_created(&stream->destroy_callbacks)) {
		array_foreach(&stream->destroy_callbacks, dc)
			dc->callback(dc->context);
		array_free(&stream->destroy_callbacks);
	}

        i_free(stream->error);
        i_free(stream->name);
        i_free(stream);
}

void io_stream_close(struct iostream_private *stream, bool close_parent)
{
	stream->close(stream, close_parent);
}

void io_stream_set_max_buffer_size(struct iostream_private *stream,
				   size_t max_size)
{
	stream->set_max_buffer_size(stream, max_size);
}

void io_stream_add_destroy_callback(struct iostream_private *stream,
				    void (*callback)(void *), void *context)
{
	struct iostream_destroy_callback *dc;

	if (!array_is_created(&stream->destroy_callbacks))
		i_array_init(&stream->destroy_callbacks, 2);
	dc = array_append_space(&stream->destroy_callbacks);
	dc->callback = callback;
	dc->context = context;
}

void io_stream_remove_destroy_callback(struct iostream_private *stream,
				       void (*callback)(void *))
{
	const struct iostream_destroy_callback *dcs;
	unsigned int i, count;

	dcs = array_get(&stream->destroy_callbacks, &count);
	for (i = 0; i < count; i++) {
		if (dcs[i].callback == callback) {
			array_delete(&stream->destroy_callbacks, i, 1);
			return;
		}
	}
	i_unreached();
}

void io_stream_set_error(struct iostream_private *stream,
			 const char *fmt, ...)
{
	va_list args;

	va_start(args, fmt);
	io_stream_set_verror(stream, fmt, args);
	va_end(args);
}

void io_stream_set_verror(struct iostream_private *stream,
			  const char *fmt, va_list args)
{
	/* one of the parameters may be the old stream->error, so don't free
	   it before the new error is created. */
	char *error = i_strdup_vprintf(fmt, args);
	i_free(stream->error);
	stream->error = error;
}

const char *io_stream_get_disconnect_reason(struct istream *input,
					    struct ostream *output)
{
	const char *errstr;

	if (input != NULL && input->stream_errno != 0) {
		errno = input->stream_errno;
		errstr = i_stream_get_error(input);
	} else if (output != NULL && output->stream_errno != 0) {
		errno = output->stream_errno;
		errstr = o_stream_get_error(output);
	} else {
		errno = 0;
		errstr = "";
	}

	if (errno == 0 || errno == EPIPE)
		return "Connection closed";
	else
		return t_strdup_printf("Connection closed: %s", errstr);
}

void io_stream_switch_ioloop_to(struct iostream_private *stream,
				struct ioloop *ioloop)
{
	stream->ioloop = ioloop;
}

struct ioloop *io_stream_get_ioloop(struct iostream_private *stream)
{
	return (stream->ioloop == NULL ? current_ioloop : stream->ioloop);
}