Coverage Report

Created: 2025-07-01 07:09

/src/glib/gio/gpollableoutputstream.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 "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
0
{
58
0
  iface->can_poll           = g_pollable_output_stream_default_can_poll;
59
0
  iface->write_nonblocking  = g_pollable_output_stream_default_write_nonblocking;
60
0
  iface->writev_nonblocking = g_pollable_output_stream_default_writev_nonblocking;
61
0
}
62
63
static gboolean
64
g_pollable_output_stream_default_can_poll (GPollableOutputStream *stream)
65
0
{
66
0
  return TRUE;
67
0
}
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
0
{
88
0
  g_return_val_if_fail (G_IS_POLLABLE_OUTPUT_STREAM (stream), FALSE);
89
90
0
  return G_POLLABLE_OUTPUT_STREAM_GET_INTERFACE (stream)->can_poll (stream);
91
0
}
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
0
{
116
0
  g_return_val_if_fail (G_IS_POLLABLE_OUTPUT_STREAM (stream), FALSE);
117
118
0
  return G_POLLABLE_OUTPUT_STREAM_GET_INTERFACE (stream)->is_writable (stream);
119
0
}
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
0
{
143
0
  g_return_val_if_fail (G_IS_POLLABLE_OUTPUT_STREAM (stream), NULL);
144
145
0
  return G_POLLABLE_OUTPUT_STREAM_GET_INTERFACE (stream)->
146
0
    create_source (stream, cancellable);
147
0
}
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
0
{
155
0
  if (!g_pollable_output_stream_is_writable (stream))
156
0
    {
157
0
      g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK,
158
0
                           g_strerror (EAGAIN));
159
0
      return -1;
160
0
    }
161
162
0
  return G_OUTPUT_STREAM_GET_CLASS (stream)->
163
0
    write_fn (G_OUTPUT_STREAM (stream), buffer, count, NULL, error);
164
0
}
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
0
{
173
0
  gsize _bytes_written = 0;
174
0
  GPollableOutputStreamInterface *iface = G_POLLABLE_OUTPUT_STREAM_GET_INTERFACE (stream);
175
0
  gsize i;
176
0
  GError *err = NULL;
177
178
0
  for (i = 0; i < n_vectors; i++)
179
0
    {
180
0
      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
0
      if (_bytes_written > G_MAXSIZE - vectors[i].size)
185
0
        break;
186
187
0
      res = iface->write_nonblocking (stream, vectors[i].buffer, vectors[i].size, &err);
188
0
      if (res == -1)
189
0
        {
190
0
          if (bytes_written)
191
0
            *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
0
          if (_bytes_written > 0)
199
0
            {
200
0
              g_clear_error (&err);
201
0
              return G_POLLABLE_RETURN_OK;
202
0
            }
203
0
          else if (g_error_matches (err, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK))
204
0
            {
205
0
              g_clear_error (&err);
206
0
              return G_POLLABLE_RETURN_WOULD_BLOCK;
207
0
            }
208
0
          else
209
0
            {
210
0
              g_propagate_error (error, err);
211
0
              return G_POLLABLE_RETURN_FAILED;
212
0
            }
213
0
        }
214
215
0
      _bytes_written += res;
216
      /* if we had a short write break the loop here */
217
0
      if ((gsize) res < vectors[i].size)
218
0
        break;
219
0
    }
220
221
0
  if (bytes_written)
222
0
    *bytes_written = _bytes_written;
223
224
0
  return G_POLLABLE_RETURN_OK;
225
0
}
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
0
{
263
0
  gssize res;
264
265
0
  g_return_val_if_fail (G_IS_POLLABLE_OUTPUT_STREAM (stream), -1);
266
0
  g_return_val_if_fail (buffer != NULL, 0);
267
268
0
  if (g_cancellable_set_error_if_cancelled (cancellable, error))
269
0
    return -1;
270
271
0
  if (count == 0)
272
0
    return 0;
273
274
0
  if (((gssize) count) < 0)
275
0
    {
276
0
      g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
277
0
       _("Too large count value passed to %s"), G_STRFUNC);
278
0
      return -1;
279
0
    }
280
281
0
  if (cancellable)
282
0
    g_cancellable_push_current (cancellable);
283
284
0
  res = G_POLLABLE_OUTPUT_STREAM_GET_INTERFACE (stream)->
285
0
    write_nonblocking (stream, buffer, count, error);
286
287
0
  if (cancellable)
288
0
    g_cancellable_pop_current (cancellable);
289
290
0
  return res;
291
0
}
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
0
{
337
0
  GPollableOutputStreamInterface *iface;
338
0
  GPollableReturn res;
339
0
  gsize _bytes_written = 0;
340
341
0
  if (bytes_written)
342
0
    *bytes_written = 0;
343
344
0
  g_return_val_if_fail (G_IS_POLLABLE_OUTPUT_STREAM (stream), G_POLLABLE_RETURN_FAILED);
345
0
  g_return_val_if_fail (vectors != NULL || n_vectors == 0, G_POLLABLE_RETURN_FAILED);
346
0
  g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), G_POLLABLE_RETURN_FAILED);
347
0
  g_return_val_if_fail (error == NULL || *error == NULL, G_POLLABLE_RETURN_FAILED);
348
349
0
  if (g_cancellable_set_error_if_cancelled (cancellable, error))
350
0
    return G_POLLABLE_RETURN_FAILED;
351
352
0
  if (n_vectors == 0)
353
0
    return G_POLLABLE_RETURN_OK;
354
355
0
  iface = G_POLLABLE_OUTPUT_STREAM_GET_INTERFACE (stream);
356
0
  g_return_val_if_fail (iface->writev_nonblocking != NULL, G_POLLABLE_RETURN_FAILED);
357
358
0
  if (cancellable)
359
0
    g_cancellable_push_current (cancellable);
360
361
0
  res = iface->
362
0
    writev_nonblocking (stream, vectors, n_vectors, &_bytes_written, error);
363
364
0
  if (cancellable)
365
0
    g_cancellable_pop_current (cancellable);
366
367
0
  if (res == G_POLLABLE_RETURN_FAILED)
368
0
    g_warn_if_fail (error == NULL || (*error != NULL && !g_error_matches (*error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK)));
369
0
  else if (res == G_POLLABLE_RETURN_WOULD_BLOCK)
370
0
    g_warn_if_fail (error == NULL || *error == NULL);
371
372
  /* in case of not-OK nothing must've been written */
373
0
  g_warn_if_fail (res == G_POLLABLE_RETURN_OK || _bytes_written == 0);
374
375
0
  if (bytes_written)
376
0
    *bytes_written = _bytes_written;
377
378
0
  return res;
379
0
}