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