1 | /* GIO - GLib Input, Output and Streaming Library |
2 | * |
3 | * Copyright (C) 2010 Red Hat, Inc. |
4 | * |
5 | * This library is free software; you can redistribute it and/or |
6 | * modify it under the terms of the GNU Lesser General Public |
7 | * License as published by the Free Software Foundation; either |
8 | * version 2.1 of the License, or (at your option) any later version. |
9 | * |
10 | * This library is distributed in the hope that it will be useful, |
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
13 | * Lesser General Public License for more details. |
14 | * |
15 | * You should have received a copy of the GNU Lesser General |
16 | * Public License along with this library; if not, see <http://www.gnu.org/licenses/>. |
17 | */ |
18 | |
19 | #include "config.h" |
20 | |
21 | #include <errno.h> |
22 | |
23 | #include "gpollableoutputstream.h" |
24 | #include "gasynchelper.h" |
25 | #include "gfiledescriptorbased.h" |
26 | #include "glibintl.h" |
27 | |
28 | /** |
29 | * SECTION:gpollableoutputstream |
30 | * @short_description: Interface for pollable output streams |
31 | * @include: gio/gio.h |
32 | * @see_also: #GOutputStream, #GFileDescriptorBased, #GPollableInputStream |
33 | * |
34 | * #GPollableOutputStream is implemented by #GOutputStreams that |
35 | * can be polled for readiness to write. This can be used when |
36 | * interfacing with a non-GIO API that expects |
37 | * UNIX-file-descriptor-style asynchronous I/O rather than GIO-style. |
38 | * |
39 | * Since: 2.28 |
40 | */ |
41 | |
42 | G_DEFINE_INTERFACE (GPollableOutputStream, g_pollable_output_stream, G_TYPE_OUTPUT_STREAM) |
43 | |
44 | static gboolean g_pollable_output_stream_default_can_poll (GPollableOutputStream *stream); |
45 | static gssize g_pollable_output_stream_default_write_nonblocking (GPollableOutputStream *stream, |
46 | const void *buffer, |
47 | gsize count, |
48 | GError **error); |
49 | static GPollableReturn g_pollable_output_stream_default_writev_nonblocking (GPollableOutputStream *stream, |
50 | const GOutputVector *vectors, |
51 | gsize n_vectors, |
52 | gsize *bytes_written, |
53 | GError **error); |
54 | |
55 | static void |
56 | g_pollable_output_stream_default_init (GPollableOutputStreamInterface *iface) |
57 | { |
58 | iface->can_poll = g_pollable_output_stream_default_can_poll; |
59 | iface->write_nonblocking = g_pollable_output_stream_default_write_nonblocking; |
60 | iface->writev_nonblocking = g_pollable_output_stream_default_writev_nonblocking; |
61 | } |
62 | |
63 | static gboolean |
64 | g_pollable_output_stream_default_can_poll (GPollableOutputStream *stream) |
65 | { |
66 | return TRUE; |
67 | } |
68 | |
69 | /** |
70 | * g_pollable_output_stream_can_poll: |
71 | * @stream: a #GPollableOutputStream. |
72 | * |
73 | * Checks if @stream is actually pollable. Some classes may implement |
74 | * #GPollableOutputStream but have only certain instances of that |
75 | * class be pollable. If this method returns %FALSE, then the behavior |
76 | * of other #GPollableOutputStream methods is undefined. |
77 | * |
78 | * For any given stream, the value returned by this method is constant; |
79 | * a stream cannot switch from pollable to non-pollable or vice versa. |
80 | * |
81 | * Returns: %TRUE if @stream is pollable, %FALSE if not. |
82 | * |
83 | * Since: 2.28 |
84 | */ |
85 | gboolean |
86 | g_pollable_output_stream_can_poll (GPollableOutputStream *stream) |
87 | { |
88 | g_return_val_if_fail (G_IS_POLLABLE_OUTPUT_STREAM (stream), FALSE); |
89 | |
90 | return G_POLLABLE_OUTPUT_STREAM_GET_INTERFACE (stream)->can_poll (stream); |
91 | } |
92 | |
93 | /** |
94 | * g_pollable_output_stream_is_writable: |
95 | * @stream: a #GPollableOutputStream. |
96 | * |
97 | * Checks if @stream can be written. |
98 | * |
99 | * Note that some stream types may not be able to implement this 100% |
100 | * reliably, and it is possible that a call to g_output_stream_write() |
101 | * after this returns %TRUE would still block. To guarantee |
102 | * non-blocking behavior, you should always use |
103 | * g_pollable_output_stream_write_nonblocking(), which will return a |
104 | * %G_IO_ERROR_WOULD_BLOCK error rather than blocking. |
105 | * |
106 | * Returns: %TRUE if @stream is writable, %FALSE if not. If an error |
107 | * has occurred on @stream, this will result in |
108 | * g_pollable_output_stream_is_writable() returning %TRUE, and the |
109 | * next attempt to write will return the error. |
110 | * |
111 | * Since: 2.28 |
112 | */ |
113 | gboolean |
114 | g_pollable_output_stream_is_writable (GPollableOutputStream *stream) |
115 | { |
116 | g_return_val_if_fail (G_IS_POLLABLE_OUTPUT_STREAM (stream), FALSE); |
117 | |
118 | return G_POLLABLE_OUTPUT_STREAM_GET_INTERFACE (stream)->is_writable (stream); |
119 | } |
120 | |
121 | /** |
122 | * g_pollable_output_stream_create_source: |
123 | * @stream: a #GPollableOutputStream. |
124 | * @cancellable: (nullable): a #GCancellable, or %NULL |
125 | * |
126 | * Creates a #GSource that triggers when @stream can be written, or |
127 | * @cancellable is triggered or an error occurs. The callback on the |
128 | * source is of the #GPollableSourceFunc type. |
129 | * |
130 | * As with g_pollable_output_stream_is_writable(), it is possible that |
131 | * the stream may not actually be writable even after the source |
132 | * triggers, so you should use g_pollable_output_stream_write_nonblocking() |
133 | * rather than g_output_stream_write() from the callback. |
134 | * |
135 | * Returns: (transfer full): a new #GSource |
136 | * |
137 | * Since: 2.28 |
138 | */ |
139 | GSource * |
140 | g_pollable_output_stream_create_source (GPollableOutputStream *stream, |
141 | GCancellable *cancellable) |
142 | { |
143 | g_return_val_if_fail (G_IS_POLLABLE_OUTPUT_STREAM (stream), NULL); |
144 | |
145 | return G_POLLABLE_OUTPUT_STREAM_GET_INTERFACE (stream)-> |
146 | create_source (stream, cancellable); |
147 | } |
148 | |
149 | static gssize |
150 | g_pollable_output_stream_default_write_nonblocking (GPollableOutputStream *stream, |
151 | const void *buffer, |
152 | gsize count, |
153 | GError **error) |
154 | { |
155 | if (!g_pollable_output_stream_is_writable (stream)) |
156 | { |
157 | g_set_error_literal (err: error, G_IO_ERROR, code: G_IO_ERROR_WOULD_BLOCK, |
158 | message: g_strerror (EAGAIN)); |
159 | return -1; |
160 | } |
161 | |
162 | return G_OUTPUT_STREAM_GET_CLASS (stream)-> |
163 | write_fn (G_OUTPUT_STREAM (stream), buffer, count, NULL, error); |
164 | } |
165 | |
166 | static GPollableReturn |
167 | g_pollable_output_stream_default_writev_nonblocking (GPollableOutputStream *stream, |
168 | const GOutputVector *vectors, |
169 | gsize n_vectors, |
170 | gsize *bytes_written, |
171 | GError **error) |
172 | { |
173 | gsize _bytes_written = 0; |
174 | GPollableOutputStreamInterface *iface = G_POLLABLE_OUTPUT_STREAM_GET_INTERFACE (stream); |
175 | gsize i; |
176 | GError *err = NULL; |
177 | |
178 | for (i = 0; i < n_vectors; i++) |
179 | { |
180 | gssize res; |
181 | |
182 | /* Would we overflow here? In that case simply return and let the caller |
183 | * handle this like a short write */ |
184 | if (_bytes_written > G_MAXSIZE - vectors[i].size) |
185 | break; |
186 | |
187 | res = iface->write_nonblocking (stream, vectors[i].buffer, vectors[i].size, &err); |
188 | if (res == -1) |
189 | { |
190 | if (bytes_written) |
191 | *bytes_written = _bytes_written; |
192 | |
193 | /* If something was written already we handle this like a short |
194 | * write and assume that the next call would either give the same |
195 | * error again or successfully finish writing without errors or data |
196 | * loss |
197 | */ |
198 | if (_bytes_written > 0) |
199 | { |
200 | g_clear_error (err: &err); |
201 | return G_POLLABLE_RETURN_OK; |
202 | } |
203 | else if (g_error_matches (error: err, G_IO_ERROR, code: G_IO_ERROR_WOULD_BLOCK)) |
204 | { |
205 | g_clear_error (err: &err); |
206 | return G_POLLABLE_RETURN_WOULD_BLOCK; |
207 | } |
208 | else |
209 | { |
210 | g_propagate_error (dest: error, src: err); |
211 | return G_POLLABLE_RETURN_FAILED; |
212 | } |
213 | } |
214 | |
215 | _bytes_written += res; |
216 | /* if we had a short write break the loop here */ |
217 | if ((gsize) res < vectors[i].size) |
218 | break; |
219 | } |
220 | |
221 | if (bytes_written) |
222 | *bytes_written = _bytes_written; |
223 | |
224 | return G_POLLABLE_RETURN_OK; |
225 | } |
226 | |
227 | /** |
228 | * g_pollable_output_stream_write_nonblocking: |
229 | * @stream: a #GPollableOutputStream |
230 | * @buffer: (array length=count) (element-type guint8): a buffer to write |
231 | * data from |
232 | * @count: the number of bytes you want to write |
233 | * @cancellable: (nullable): a #GCancellable, or %NULL |
234 | * @error: #GError for error reporting, or %NULL to ignore. |
235 | * |
236 | * Attempts to write up to @count bytes from @buffer to @stream, as |
237 | * with g_output_stream_write(). If @stream is not currently writable, |
238 | * this will immediately return %G_IO_ERROR_WOULD_BLOCK, and you can |
239 | * use g_pollable_output_stream_create_source() to create a #GSource |
240 | * that will be triggered when @stream is writable. |
241 | * |
242 | * Note that since this method never blocks, you cannot actually |
243 | * use @cancellable to cancel it. However, it will return an error |
244 | * if @cancellable has already been cancelled when you call, which |
245 | * may happen if you call this method after a source triggers due |
246 | * to having been cancelled. |
247 | * |
248 | * Also note that if %G_IO_ERROR_WOULD_BLOCK is returned some underlying |
249 | * transports like D/TLS require that you re-send the same @buffer and |
250 | * @count in the next write call. |
251 | * |
252 | * Virtual: write_nonblocking |
253 | * Returns: the number of bytes written, or -1 on error (including |
254 | * %G_IO_ERROR_WOULD_BLOCK). |
255 | */ |
256 | gssize |
257 | g_pollable_output_stream_write_nonblocking (GPollableOutputStream *stream, |
258 | const void *buffer, |
259 | gsize count, |
260 | GCancellable *cancellable, |
261 | GError **error) |
262 | { |
263 | gssize res; |
264 | |
265 | g_return_val_if_fail (G_IS_POLLABLE_OUTPUT_STREAM (stream), -1); |
266 | g_return_val_if_fail (buffer != NULL, 0); |
267 | |
268 | if (g_cancellable_set_error_if_cancelled (cancellable, error)) |
269 | return -1; |
270 | |
271 | if (count == 0) |
272 | return 0; |
273 | |
274 | if (((gssize) count) < 0) |
275 | { |
276 | g_set_error (err: error, G_IO_ERROR, code: G_IO_ERROR_INVALID_ARGUMENT, |
277 | _("Too large count value passed to %s" ), G_STRFUNC); |
278 | return -1; |
279 | } |
280 | |
281 | if (cancellable) |
282 | g_cancellable_push_current (cancellable); |
283 | |
284 | res = G_POLLABLE_OUTPUT_STREAM_GET_INTERFACE (stream)-> |
285 | write_nonblocking (stream, buffer, count, error); |
286 | |
287 | if (cancellable) |
288 | g_cancellable_pop_current (cancellable); |
289 | |
290 | return res; |
291 | } |
292 | |
293 | /** |
294 | * g_pollable_output_stream_writev_nonblocking: |
295 | * @stream: a #GPollableOutputStream |
296 | * @vectors: (array length=n_vectors): the buffer containing the #GOutputVectors to write. |
297 | * @n_vectors: the number of vectors to write |
298 | * @bytes_written: (out) (optional): location to store the number of bytes that were |
299 | * written to the stream |
300 | * @cancellable: (nullable): a #GCancellable, or %NULL |
301 | * @error: #GError for error reporting, or %NULL to ignore. |
302 | * |
303 | * Attempts to write the bytes contained in the @n_vectors @vectors to @stream, |
304 | * as with g_output_stream_writev(). If @stream is not currently writable, |
305 | * this will immediately return %@G_POLLABLE_RETURN_WOULD_BLOCK, and you can |
306 | * use g_pollable_output_stream_create_source() to create a #GSource |
307 | * that will be triggered when @stream is writable. @error will *not* be |
308 | * set in that case. |
309 | * |
310 | * Note that since this method never blocks, you cannot actually |
311 | * use @cancellable to cancel it. However, it will return an error |
312 | * if @cancellable has already been cancelled when you call, which |
313 | * may happen if you call this method after a source triggers due |
314 | * to having been cancelled. |
315 | * |
316 | * Also note that if %G_POLLABLE_RETURN_WOULD_BLOCK is returned some underlying |
317 | * transports like D/TLS require that you re-send the same @vectors and |
318 | * @n_vectors in the next write call. |
319 | * |
320 | * Virtual: writev_nonblocking |
321 | * |
322 | * Returns: %@G_POLLABLE_RETURN_OK on success, %G_POLLABLE_RETURN_WOULD_BLOCK |
323 | * if the stream is not currently writable (and @error is *not* set), or |
324 | * %G_POLLABLE_RETURN_FAILED if there was an error in which case @error will |
325 | * be set. |
326 | * |
327 | * Since: 2.60 |
328 | */ |
329 | GPollableReturn |
330 | g_pollable_output_stream_writev_nonblocking (GPollableOutputStream *stream, |
331 | const GOutputVector *vectors, |
332 | gsize n_vectors, |
333 | gsize *bytes_written, |
334 | GCancellable *cancellable, |
335 | GError **error) |
336 | { |
337 | GPollableOutputStreamInterface *iface; |
338 | GPollableReturn res; |
339 | gsize _bytes_written = 0; |
340 | |
341 | if (bytes_written) |
342 | *bytes_written = 0; |
343 | |
344 | g_return_val_if_fail (G_IS_POLLABLE_OUTPUT_STREAM (stream), G_POLLABLE_RETURN_FAILED); |
345 | g_return_val_if_fail (vectors != NULL || n_vectors == 0, G_POLLABLE_RETURN_FAILED); |
346 | g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), G_POLLABLE_RETURN_FAILED); |
347 | g_return_val_if_fail (error == NULL || *error == NULL, G_POLLABLE_RETURN_FAILED); |
348 | |
349 | if (g_cancellable_set_error_if_cancelled (cancellable, error)) |
350 | return G_POLLABLE_RETURN_FAILED; |
351 | |
352 | if (n_vectors == 0) |
353 | return G_POLLABLE_RETURN_OK; |
354 | |
355 | iface = G_POLLABLE_OUTPUT_STREAM_GET_INTERFACE (stream); |
356 | g_return_val_if_fail (iface->writev_nonblocking != NULL, G_POLLABLE_RETURN_FAILED); |
357 | |
358 | if (cancellable) |
359 | g_cancellable_push_current (cancellable); |
360 | |
361 | res = iface-> |
362 | writev_nonblocking (stream, vectors, n_vectors, &_bytes_written, error); |
363 | |
364 | if (cancellable) |
365 | g_cancellable_pop_current (cancellable); |
366 | |
367 | if (res == G_POLLABLE_RETURN_FAILED) |
368 | g_warn_if_fail (error == NULL || (*error != NULL && !g_error_matches (*error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK))); |
369 | else if (res == G_POLLABLE_RETURN_WOULD_BLOCK) |
370 | g_warn_if_fail (error == NULL || *error == NULL); |
371 | |
372 | /* in case of not-OK nothing must've been written */ |
373 | g_warn_if_fail (res == G_POLLABLE_RETURN_OK || _bytes_written == 0); |
374 | |
375 | if (bytes_written) |
376 | *bytes_written = _bytes_written; |
377 | |
378 | return res; |
379 | } |
380 | |