/src/dovecot/src/lib/iostream.c
Line | Count | Source |
1 | | /* Copyright (c) Dovecot authors, see top-level COPYING file */ |
2 | | |
3 | | #include "lib.h" |
4 | | #include "array.h" |
5 | | #include "istream.h" |
6 | | #include "ostream.h" |
7 | | #include "iostream-private.h" |
8 | | |
9 | | struct iostream_fd *iostream_fd_init(int fd) |
10 | 0 | { |
11 | 0 | struct iostream_fd *ref = i_new(struct iostream_fd, 1); |
12 | 0 | ref->refcount = 1; |
13 | 0 | ref->fd = fd; |
14 | 0 | return ref; |
15 | 0 | } |
16 | | |
17 | | void iostream_fd_ref(struct iostream_fd *ref) |
18 | 0 | { |
19 | 0 | i_assert(ref->refcount > 0); |
20 | 0 | ref->refcount++; |
21 | 0 | } |
22 | | |
23 | | bool iostream_fd_unref(struct iostream_fd **_ref) |
24 | 0 | { |
25 | 0 | struct iostream_fd *ref = *_ref; |
26 | |
|
27 | 0 | i_assert(ref != NULL); |
28 | 0 | i_assert(ref->refcount > 0); |
29 | | |
30 | 0 | *_ref = NULL; |
31 | |
|
32 | 0 | if (--ref->refcount > 0) |
33 | 0 | return TRUE; |
34 | 0 | i_free(ref); |
35 | 0 | return FALSE; |
36 | 0 | } |
37 | | |
38 | | void io_stream_create_fd_autoclose(int *fd, size_t max_in_buffer_size, |
39 | | size_t max_out_buffer_size, |
40 | | struct istream **input_r, |
41 | | struct ostream **output_r) |
42 | 0 | { |
43 | 0 | struct iostream_fd *fd_ref = iostream_fd_init(*fd); |
44 | 0 | *input_r = i_stream_create_fd_ref_autoclose(fd_ref, max_in_buffer_size); |
45 | 0 | *output_r = o_stream_create_fd_ref_autoclose(fd_ref, max_out_buffer_size); |
46 | 0 | iostream_fd_unref(&fd_ref); |
47 | 0 | *fd = -1; |
48 | 0 | } |
49 | | |
50 | | static void |
51 | | io_stream_default_close(struct iostream_private *stream ATTR_UNUSED, |
52 | | bool close_parent ATTR_UNUSED) |
53 | 0 | { |
54 | 0 | } |
55 | | |
56 | | static void |
57 | | io_stream_default_destroy(struct iostream_private *stream ATTR_UNUSED) |
58 | 0 | { |
59 | 0 | } |
60 | | |
61 | | void io_stream_init(struct iostream_private *stream) |
62 | 8.63k | { |
63 | 8.63k | if (stream->close == NULL) |
64 | 0 | stream->close = io_stream_default_close; |
65 | 8.63k | if (stream->destroy == NULL) |
66 | 0 | stream->destroy = io_stream_default_destroy; |
67 | 8.63k | stream->ioloop = current_ioloop; |
68 | | |
69 | 8.63k | stream->refcount = 1; |
70 | 8.63k | } |
71 | | |
72 | | void io_stream_ref(struct iostream_private *stream) |
73 | 0 | { |
74 | 0 | i_assert(stream->refcount > 0); |
75 | | |
76 | 0 | stream->refcount++; |
77 | 0 | } |
78 | | |
79 | | bool io_stream_unref(struct iostream_private *stream) |
80 | 8.63k | { |
81 | 8.63k | i_assert(stream->refcount > 0); |
82 | 8.63k | if (--stream->refcount != 0) |
83 | 0 | return TRUE; |
84 | | |
85 | 8.63k | stream->close(stream, FALSE); |
86 | 8.63k | stream->destroy(stream); |
87 | 8.63k | return FALSE; |
88 | 8.63k | } |
89 | | |
90 | | void io_stream_free(struct iostream_private *stream) |
91 | 8.63k | { |
92 | 8.63k | const struct iostream_destroy_callback *dc; |
93 | | |
94 | 8.63k | if (array_is_created(&stream->destroy_callbacks)) { |
95 | 0 | array_foreach(&stream->destroy_callbacks, dc) |
96 | 0 | dc->callback(dc->context); |
97 | 0 | array_free(&stream->destroy_callbacks); |
98 | 0 | } |
99 | | |
100 | 8.63k | i_free(stream->error); |
101 | 8.63k | i_free(stream->name); |
102 | 8.63k | i_free(stream); |
103 | 8.63k | } |
104 | | |
105 | | void io_stream_close(struct iostream_private *stream, bool close_parent) |
106 | 0 | { |
107 | 0 | stream->close(stream, close_parent); |
108 | 0 | } |
109 | | |
110 | | void io_stream_set_max_buffer_size(struct iostream_private *stream, |
111 | | size_t max_size) |
112 | 0 | { |
113 | 0 | stream->set_max_buffer_size(stream, max_size); |
114 | 0 | } |
115 | | |
116 | | void io_stream_add_destroy_callback(struct iostream_private *stream, |
117 | | void (*callback)(void *), void *context) |
118 | 0 | { |
119 | 0 | struct iostream_destroy_callback *dc; |
120 | |
|
121 | 0 | if (!array_is_created(&stream->destroy_callbacks)) |
122 | 0 | i_array_init(&stream->destroy_callbacks, 2); |
123 | 0 | dc = array_append_space(&stream->destroy_callbacks); |
124 | 0 | dc->callback = callback; |
125 | 0 | dc->context = context; |
126 | 0 | } |
127 | | |
128 | | void io_stream_remove_destroy_callback(struct iostream_private *stream, |
129 | | void (*callback)(void *)) |
130 | 0 | { |
131 | 0 | const struct iostream_destroy_callback *dcs; |
132 | 0 | unsigned int i, count; |
133 | |
|
134 | 0 | dcs = array_get(&stream->destroy_callbacks, &count); |
135 | 0 | for (i = 0; i < count; i++) { |
136 | 0 | if (dcs[i].callback == callback) { |
137 | 0 | array_delete(&stream->destroy_callbacks, i, 1); |
138 | 0 | return; |
139 | 0 | } |
140 | 0 | } |
141 | 0 | i_unreached(); |
142 | 0 | } |
143 | | |
144 | | void io_stream_set_error(struct iostream_private *stream, |
145 | | const char *fmt, ...) |
146 | 0 | { |
147 | 0 | va_list args; |
148 | |
|
149 | 0 | va_start(args, fmt); |
150 | 0 | io_stream_set_verror(stream, fmt, args); |
151 | 0 | va_end(args); |
152 | 0 | } |
153 | | |
154 | | void io_stream_set_verror(struct iostream_private *stream, |
155 | | const char *fmt, va_list args) |
156 | 0 | { |
157 | | /* one of the parameters may be the old stream->error, so don't free |
158 | | it before the new error is created. */ |
159 | 0 | char *error = i_strdup_vprintf(fmt, args); |
160 | 0 | i_free(stream->error); |
161 | 0 | stream->error = error; |
162 | 0 | } |
163 | | |
164 | | const char *io_stream_get_disconnect_reason(struct istream *input, |
165 | | struct ostream *output) |
166 | 0 | { |
167 | 0 | const char *errstr; |
168 | |
|
169 | 0 | if (input != NULL && input->stream_errno != 0) { |
170 | 0 | errno = input->stream_errno; |
171 | 0 | errstr = i_stream_get_error(input); |
172 | 0 | } else if (output != NULL && output->stream_errno != 0) { |
173 | 0 | errno = output->stream_errno; |
174 | 0 | errstr = o_stream_get_error(output); |
175 | 0 | } else { |
176 | 0 | errno = 0; |
177 | 0 | errstr = ""; |
178 | 0 | } |
179 | |
|
180 | 0 | if (errno == 0 || errno == EPIPE) |
181 | 0 | return "Connection closed"; |
182 | 0 | else |
183 | 0 | return t_strdup_printf("Connection closed: %s", errstr); |
184 | 0 | } |
185 | | |
186 | | void io_stream_switch_ioloop_to(struct iostream_private *stream, |
187 | | struct ioloop *ioloop) |
188 | 0 | { |
189 | 0 | stream->ioloop = ioloop; |
190 | 0 | } |
191 | | |
192 | | struct ioloop *io_stream_get_ioloop(struct iostream_private *stream) |
193 | 0 | { |
194 | 0 | return (stream->ioloop == NULL ? current_ioloop : stream->ioloop); |
195 | 0 | } |