/src/glib/gio/gpollableutils.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* GIO - GLib Input, Output and Streaming Library |
2 | | * |
3 | | * Copyright (C) 2010 Red Hat, Inc. |
4 | | * |
5 | | * SPDX-License-Identifier: LGPL-2.1-or-later |
6 | | * |
7 | | * This library is free software; you can redistribute it and/or |
8 | | * modify it under the terms of the GNU Lesser General Public |
9 | | * License as published by the Free Software Foundation; either |
10 | | * version 2.1 of the License, or (at your option) any later version. |
11 | | * |
12 | | * This library is distributed in the hope that it will be useful, |
13 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
15 | | * Lesser General Public License for more details. |
16 | | * |
17 | | * You should have received a copy of the GNU Lesser General |
18 | | * Public License along with this library; if not, see <http://www.gnu.org/licenses/>. |
19 | | */ |
20 | | |
21 | | #include "config.h" |
22 | | |
23 | | #include <errno.h> |
24 | | |
25 | | #include "gpollableinputstream.h" |
26 | | #include "gasynchelper.h" |
27 | | #include "glibintl.h" |
28 | | |
29 | | /** |
30 | | * SECTION:gpollableutils |
31 | | * @short_description: Utilities for pollable streams |
32 | | * @include: gio/gio.h |
33 | | * |
34 | | * Utility functions for #GPollableInputStream and |
35 | | * #GPollableOutputStream implementations. |
36 | | */ |
37 | | |
38 | | typedef struct { |
39 | | GSource source; |
40 | | |
41 | | GObject *stream; |
42 | | } GPollableSource; |
43 | | |
44 | | static gboolean |
45 | | pollable_source_dispatch (GSource *source, |
46 | | GSourceFunc callback, |
47 | | gpointer user_data) |
48 | 0 | { |
49 | 0 | GPollableSourceFunc func = (GPollableSourceFunc)callback; |
50 | 0 | GPollableSource *pollable_source = (GPollableSource *)source; |
51 | |
|
52 | 0 | return (*func) (pollable_source->stream, user_data); |
53 | 0 | } |
54 | | |
55 | | static void |
56 | | pollable_source_finalize (GSource *source) |
57 | 0 | { |
58 | 0 | GPollableSource *pollable_source = (GPollableSource *)source; |
59 | |
|
60 | 0 | g_object_unref (pollable_source->stream); |
61 | 0 | } |
62 | | |
63 | | static gboolean |
64 | | pollable_source_closure_callback (GObject *stream, |
65 | | gpointer data) |
66 | 0 | { |
67 | 0 | GClosure *closure = data; |
68 | |
|
69 | 0 | GValue param = G_VALUE_INIT; |
70 | 0 | GValue result_value = G_VALUE_INIT; |
71 | 0 | gboolean result; |
72 | |
|
73 | 0 | g_value_init (&result_value, G_TYPE_BOOLEAN); |
74 | |
|
75 | 0 | g_value_init (¶m, G_TYPE_OBJECT); |
76 | 0 | g_value_set_object (¶m, stream); |
77 | |
|
78 | 0 | g_closure_invoke (closure, &result_value, 1, ¶m, NULL); |
79 | |
|
80 | 0 | result = g_value_get_boolean (&result_value); |
81 | 0 | g_value_unset (&result_value); |
82 | 0 | g_value_unset (¶m); |
83 | |
|
84 | 0 | return result; |
85 | 0 | } |
86 | | |
87 | | static GSourceFuncs pollable_source_funcs = |
88 | | { |
89 | | NULL, |
90 | | NULL, |
91 | | pollable_source_dispatch, |
92 | | pollable_source_finalize, |
93 | | (GSourceFunc)pollable_source_closure_callback, |
94 | | NULL, |
95 | | }; |
96 | | |
97 | | /** |
98 | | * g_pollable_source_new: |
99 | | * @pollable_stream: the stream associated with the new source |
100 | | * |
101 | | * Utility method for #GPollableInputStream and #GPollableOutputStream |
102 | | * implementations. Creates a new #GSource that expects a callback of |
103 | | * type #GPollableSourceFunc. The new source does not actually do |
104 | | * anything on its own; use g_source_add_child_source() to add other |
105 | | * sources to it to cause it to trigger. |
106 | | * |
107 | | * Returns: (transfer full): the new #GSource. |
108 | | * |
109 | | * Since: 2.28 |
110 | | */ |
111 | | GSource * |
112 | | g_pollable_source_new (GObject *pollable_stream) |
113 | 0 | { |
114 | 0 | GSource *source; |
115 | 0 | GPollableSource *pollable_source; |
116 | |
|
117 | 0 | g_return_val_if_fail (G_IS_POLLABLE_INPUT_STREAM (pollable_stream) || |
118 | 0 | G_IS_POLLABLE_OUTPUT_STREAM (pollable_stream), NULL); |
119 | | |
120 | 0 | source = g_source_new (&pollable_source_funcs, sizeof (GPollableSource)); |
121 | 0 | g_source_set_static_name (source, "GPollableSource"); |
122 | 0 | pollable_source = (GPollableSource *)source; |
123 | 0 | pollable_source->stream = g_object_ref (pollable_stream); |
124 | |
|
125 | 0 | return source; |
126 | 0 | } |
127 | | |
128 | | /** |
129 | | * g_pollable_source_new_full: |
130 | | * @pollable_stream: (type GObject): the stream associated with the |
131 | | * new source |
132 | | * @child_source: (nullable): optional child source to attach |
133 | | * @cancellable: (nullable): optional #GCancellable to attach |
134 | | * |
135 | | * Utility method for #GPollableInputStream and #GPollableOutputStream |
136 | | * implementations. Creates a new #GSource, as with |
137 | | * g_pollable_source_new(), but also attaching @child_source (with a |
138 | | * dummy callback), and @cancellable, if they are non-%NULL. |
139 | | * |
140 | | * Returns: (transfer full): the new #GSource. |
141 | | * |
142 | | * Since: 2.34 |
143 | | */ |
144 | | GSource * |
145 | | g_pollable_source_new_full (gpointer pollable_stream, |
146 | | GSource *child_source, |
147 | | GCancellable *cancellable) |
148 | 0 | { |
149 | 0 | GSource *source; |
150 | |
|
151 | 0 | g_return_val_if_fail (G_IS_POLLABLE_INPUT_STREAM (pollable_stream) || |
152 | 0 | G_IS_POLLABLE_OUTPUT_STREAM (pollable_stream), NULL); |
153 | | |
154 | 0 | source = g_pollable_source_new (pollable_stream); |
155 | 0 | if (child_source) |
156 | 0 | { |
157 | 0 | g_source_set_dummy_callback (child_source); |
158 | 0 | g_source_add_child_source (source, child_source); |
159 | 0 | } |
160 | 0 | if (cancellable) |
161 | 0 | { |
162 | 0 | GSource *cancellable_source = g_cancellable_source_new (cancellable); |
163 | |
|
164 | 0 | g_source_set_dummy_callback (cancellable_source); |
165 | 0 | g_source_add_child_source (source, cancellable_source); |
166 | 0 | g_source_unref (cancellable_source); |
167 | 0 | } |
168 | |
|
169 | 0 | return source; |
170 | 0 | } |
171 | | |
172 | | /** |
173 | | * g_pollable_stream_read: |
174 | | * @stream: a #GInputStream |
175 | | * @buffer: (array length=count) (element-type guint8): a buffer to |
176 | | * read data into |
177 | | * @count: the number of bytes to read |
178 | | * @blocking: whether to do blocking I/O |
179 | | * @cancellable: (nullable): optional #GCancellable object, %NULL to ignore. |
180 | | * @error: location to store the error occurring, or %NULL to ignore |
181 | | * |
182 | | * Tries to read from @stream, as with g_input_stream_read() (if |
183 | | * @blocking is %TRUE) or g_pollable_input_stream_read_nonblocking() |
184 | | * (if @blocking is %FALSE). This can be used to more easily share |
185 | | * code between blocking and non-blocking implementations of a method. |
186 | | * |
187 | | * If @blocking is %FALSE, then @stream must be a |
188 | | * #GPollableInputStream for which g_pollable_input_stream_can_poll() |
189 | | * returns %TRUE, or else the behavior is undefined. If @blocking is |
190 | | * %TRUE, then @stream does not need to be a #GPollableInputStream. |
191 | | * |
192 | | * Returns: the number of bytes read, or -1 on error. |
193 | | * |
194 | | * Since: 2.34 |
195 | | */ |
196 | | gssize |
197 | | g_pollable_stream_read (GInputStream *stream, |
198 | | void *buffer, |
199 | | gsize count, |
200 | | gboolean blocking, |
201 | | GCancellable *cancellable, |
202 | | GError **error) |
203 | 0 | { |
204 | 0 | if (blocking) |
205 | 0 | { |
206 | 0 | return g_input_stream_read (stream, |
207 | 0 | buffer, count, |
208 | 0 | cancellable, error); |
209 | 0 | } |
210 | 0 | else |
211 | 0 | { |
212 | 0 | return g_pollable_input_stream_read_nonblocking (G_POLLABLE_INPUT_STREAM (stream), |
213 | 0 | buffer, count, |
214 | 0 | cancellable, error); |
215 | 0 | } |
216 | 0 | } |
217 | | |
218 | | /** |
219 | | * g_pollable_stream_write: |
220 | | * @stream: a #GOutputStream. |
221 | | * @buffer: (array length=count) (element-type guint8): the buffer |
222 | | * containing the data to write. |
223 | | * @count: the number of bytes to write |
224 | | * @blocking: whether to do blocking I/O |
225 | | * @cancellable: (nullable): optional #GCancellable object, %NULL to ignore. |
226 | | * @error: location to store the error occurring, or %NULL to ignore |
227 | | * |
228 | | * Tries to write to @stream, as with g_output_stream_write() (if |
229 | | * @blocking is %TRUE) or g_pollable_output_stream_write_nonblocking() |
230 | | * (if @blocking is %FALSE). This can be used to more easily share |
231 | | * code between blocking and non-blocking implementations of a method. |
232 | | * |
233 | | * If @blocking is %FALSE, then @stream must be a |
234 | | * #GPollableOutputStream for which |
235 | | * g_pollable_output_stream_can_poll() returns %TRUE or else the |
236 | | * behavior is undefined. If @blocking is %TRUE, then @stream does not |
237 | | * need to be a #GPollableOutputStream. |
238 | | * |
239 | | * Returns: the number of bytes written, or -1 on error. |
240 | | * |
241 | | * Since: 2.34 |
242 | | */ |
243 | | gssize |
244 | | g_pollable_stream_write (GOutputStream *stream, |
245 | | const void *buffer, |
246 | | gsize count, |
247 | | gboolean blocking, |
248 | | GCancellable *cancellable, |
249 | | GError **error) |
250 | 0 | { |
251 | 0 | if (blocking) |
252 | 0 | { |
253 | 0 | return g_output_stream_write (stream, |
254 | 0 | buffer, count, |
255 | 0 | cancellable, error); |
256 | 0 | } |
257 | 0 | else |
258 | 0 | { |
259 | 0 | return g_pollable_output_stream_write_nonblocking (G_POLLABLE_OUTPUT_STREAM (stream), |
260 | 0 | buffer, count, |
261 | 0 | cancellable, error); |
262 | 0 | } |
263 | 0 | } |
264 | | |
265 | | /** |
266 | | * g_pollable_stream_write_all: |
267 | | * @stream: a #GOutputStream. |
268 | | * @buffer: (array length=count) (element-type guint8): the buffer |
269 | | * containing the data to write. |
270 | | * @count: the number of bytes to write |
271 | | * @blocking: whether to do blocking I/O |
272 | | * @bytes_written: (out): location to store the number of bytes that was |
273 | | * written to the stream |
274 | | * @cancellable: (nullable): optional #GCancellable object, %NULL to ignore. |
275 | | * @error: location to store the error occurring, or %NULL to ignore |
276 | | * |
277 | | * Tries to write @count bytes to @stream, as with |
278 | | * g_output_stream_write_all(), but using g_pollable_stream_write() |
279 | | * rather than g_output_stream_write(). |
280 | | * |
281 | | * On a successful write of @count bytes, %TRUE is returned, and |
282 | | * @bytes_written is set to @count. |
283 | | * |
284 | | * If there is an error during the operation (including |
285 | | * %G_IO_ERROR_WOULD_BLOCK in the non-blocking case), %FALSE is |
286 | | * returned and @error is set to indicate the error status, |
287 | | * @bytes_written is updated to contain the number of bytes written |
288 | | * into the stream before the error occurred. |
289 | | * |
290 | | * As with g_pollable_stream_write(), if @blocking is %FALSE, then |
291 | | * @stream must be a #GPollableOutputStream for which |
292 | | * g_pollable_output_stream_can_poll() returns %TRUE or else the |
293 | | * behavior is undefined. If @blocking is %TRUE, then @stream does not |
294 | | * need to be a #GPollableOutputStream. |
295 | | * |
296 | | * Returns: %TRUE on success, %FALSE if there was an error |
297 | | * |
298 | | * Since: 2.34 |
299 | | */ |
300 | | gboolean |
301 | | g_pollable_stream_write_all (GOutputStream *stream, |
302 | | const void *buffer, |
303 | | gsize count, |
304 | | gboolean blocking, |
305 | | gsize *bytes_written, |
306 | | GCancellable *cancellable, |
307 | | GError **error) |
308 | 0 | { |
309 | 0 | gsize _bytes_written; |
310 | 0 | gssize res; |
311 | |
|
312 | 0 | _bytes_written = 0; |
313 | 0 | while (_bytes_written < count) |
314 | 0 | { |
315 | 0 | res = g_pollable_stream_write (stream, |
316 | 0 | (char *)buffer + _bytes_written, |
317 | 0 | count - _bytes_written, |
318 | 0 | blocking, |
319 | 0 | cancellable, error); |
320 | 0 | if (res == -1) |
321 | 0 | { |
322 | 0 | if (bytes_written) |
323 | 0 | *bytes_written = _bytes_written; |
324 | 0 | return FALSE; |
325 | 0 | } |
326 | | |
327 | 0 | if (res == 0) |
328 | 0 | g_warning ("Write returned zero without error"); |
329 | |
|
330 | 0 | _bytes_written += res; |
331 | 0 | } |
332 | | |
333 | 0 | if (bytes_written) |
334 | 0 | *bytes_written = _bytes_written; |
335 | |
|
336 | 0 | return TRUE; |
337 | 0 | } |