1 /* GIO - GLib Input, Output and Streaming Library
2 *
3 * Copyright (C) 2006-2007 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 * Author: Alexander Larsson <alexl@redhat.com>
21 */
22
23 #include "config.h"
24
25 #include <unistd.h>
26 #include <errno.h>
27 #include <stdio.h>
28 #include <sys/uio.h>
29
30 #include <glib.h>
31 #include <glib/gstdio.h>
32 #include <glib/glib-unix.h>
33 #include "gioerror.h"
34 #include "gunixoutputstream.h"
35 #include "gcancellable.h"
36 #include "gasynchelper.h"
37 #include "gfiledescriptorbased.h"
38 #include "glibintl.h"
39 #include "gioprivate.h"
40 #include "giounix-private.h"
41
42
43 /**
44 * GUnixOutputStream:
45 *
46 * `GUnixOutputStream` implements [class@Gio.OutputStream] for writing to a UNIX
47 * file descriptor, including asynchronous operations. (If the file
48 * descriptor refers to a socket or pipe, this will use `poll()` to do
49 * asynchronous I/O. If it refers to a regular file, it will fall back
50 * to doing asynchronous I/O in another thread.)
51 *
52 * Note that `<gio/gunixoutputstream.h>` belongs to the UNIX-specific GIO
53 * interfaces, thus you have to use the `gio-unix-2.0.pc` pkg-config file
54 * when using it.
55 */
56
57 enum {
58 PROP_0,
59 PROP_FD,
60 PROP_CLOSE_FD
61 };
62
63 struct _GUnixOutputStreamPrivate {
64 int fd;
65 guint close_fd : 1;
66 guint can_poll : 1;
67 };
68
69 static void g_unix_output_stream_pollable_iface_init (GPollableOutputStreamInterface *iface);
70 static void g_unix_output_stream_file_descriptor_based_iface_init (GFileDescriptorBasedIface *iface);
71
72 G_DEFINE_TYPE_WITH_CODE (GUnixOutputStream, g_unix_output_stream, G_TYPE_OUTPUT_STREAM,
73 G_ADD_PRIVATE (GUnixOutputStream)
74 G_IMPLEMENT_INTERFACE (G_TYPE_POLLABLE_OUTPUT_STREAM,
75 g_unix_output_stream_pollable_iface_init)
76 G_IMPLEMENT_INTERFACE (G_TYPE_FILE_DESCRIPTOR_BASED,
77 g_unix_output_stream_file_descriptor_based_iface_init)
78 )
79
80 static void g_unix_output_stream_set_property (GObject *object,
81 guint prop_id,
82 const GValue *value,
83 GParamSpec *pspec);
84 static void g_unix_output_stream_get_property (GObject *object,
85 guint prop_id,
86 GValue *value,
87 GParamSpec *pspec);
88 static gssize g_unix_output_stream_write (GOutputStream *stream,
89 const void *buffer,
90 gsize count,
91 GCancellable *cancellable,
92 GError **error);
93 static gboolean g_unix_output_stream_writev (GOutputStream *stream,
94 const GOutputVector *vectors,
95 gsize n_vectors,
96 gsize *bytes_written,
97 GCancellable *cancellable,
98 GError **error);
99 static gboolean g_unix_output_stream_close (GOutputStream *stream,
100 GCancellable *cancellable,
101 GError **error);
102
103 static gboolean g_unix_output_stream_pollable_can_poll (GPollableOutputStream *stream);
104 static gboolean g_unix_output_stream_pollable_is_writable (GPollableOutputStream *stream);
105 static GSource *g_unix_output_stream_pollable_create_source (GPollableOutputStream *stream,
106 GCancellable *cancellable);
107 static GPollableReturn g_unix_output_stream_pollable_writev_nonblocking (GPollableOutputStream *stream,
108 const GOutputVector *vectors,
109 gsize n_vectors,
110 gsize *bytes_written,
111 GError **error);
112
113 static void
114 g_unix_output_stream_class_init (GUnixOutputStreamClass *klass)
115 {
116 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
117 GOutputStreamClass *stream_class = G_OUTPUT_STREAM_CLASS (klass);
118
119 gobject_class->get_property = g_unix_output_stream_get_property;
120 gobject_class->set_property = g_unix_output_stream_set_property;
121
122 stream_class->write_fn = g_unix_output_stream_write;
123 stream_class->writev_fn = g_unix_output_stream_writev;
124 stream_class->close_fn = g_unix_output_stream_close;
125
126 /**
127 * GUnixOutputStream:fd:
128 *
129 * The file descriptor that the stream writes to.
130 *
131 * Since: 2.20
132 */
133 g_object_class_install_property (gobject_class,
134 PROP_FD,
135 g_param_spec_int ("fd", NULL, NULL,
136 G_MININT, G_MAXINT, -1,
137 G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
138
139 /**
140 * GUnixOutputStream:close-fd:
141 *
142 * Whether to close the file descriptor when the stream is closed.
143 *
144 * Since: 2.20
145 */
146 g_object_class_install_property (gobject_class,
147 PROP_CLOSE_FD,
148 g_param_spec_boolean ("close-fd", NULL, NULL,
149 TRUE,
150 G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
151 }
152
153 static void
154 g_unix_output_stream_pollable_iface_init (GPollableOutputStreamInterface *iface)
155 {
156 iface->can_poll = g_unix_output_stream_pollable_can_poll;
157 iface->is_writable = g_unix_output_stream_pollable_is_writable;
158 iface->create_source = g_unix_output_stream_pollable_create_source;
159 iface->writev_nonblocking = g_unix_output_stream_pollable_writev_nonblocking;
160 }
161
162 static void
163 g_unix_output_stream_file_descriptor_based_iface_init (GFileDescriptorBasedIface *iface)
164 {
165 iface->get_fd = (int (*) (GFileDescriptorBased *))g_unix_output_stream_get_fd;
166 }
167
168 static void
169 g_unix_output_stream_set_property (GObject *object,
170 guint prop_id,
171 const GValue *value,
172 GParamSpec *pspec)
173 {
174 GUnixOutputStream *unix_stream;
175
176 unix_stream = G_UNIX_OUTPUT_STREAM (object);
177
178 switch (prop_id)
179 {
180 case PROP_FD:
181 unix_stream->priv->fd = g_value_get_int (value);
182 unix_stream->priv->can_poll = _g_fd_is_pollable (unix_stream->priv->fd);
183 break;
184 case PROP_CLOSE_FD:
185 unix_stream->priv->close_fd = g_value_get_boolean (value);
186 break;
187 default:
188 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
189 break;
190 }
191 }
192
193 static void
194 g_unix_output_stream_get_property (GObject *object,
195 guint prop_id,
196 GValue *value,
197 GParamSpec *pspec)
198 {
199 GUnixOutputStream *unix_stream;
200
201 unix_stream = G_UNIX_OUTPUT_STREAM (object);
202
203 switch (prop_id)
204 {
205 case PROP_FD:
206 g_value_set_int (value, unix_stream->priv->fd);
207 break;
208 case PROP_CLOSE_FD:
209 g_value_set_boolean (value, unix_stream->priv->close_fd);
210 break;
211 default:
212 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
213 }
214 }
215
216 static void
217 g_unix_output_stream_init (GUnixOutputStream *unix_stream)
218 {
219 unix_stream->priv = g_unix_output_stream_get_instance_private (unix_stream);
220 unix_stream->priv->fd = -1;
221 unix_stream->priv->close_fd = TRUE;
222 }
223
224 /**
225 * g_unix_output_stream_new:
226 * @fd: a UNIX file descriptor
227 * @close_fd: %TRUE to close the file descriptor when done
228 *
229 * Creates a new #GUnixOutputStream for the given @fd.
230 *
231 * If @close_fd, is %TRUE, the file descriptor will be closed when
232 * the output stream is destroyed.
233 *
234 * Returns: a new #GOutputStream
235 **/
236 GOutputStream *
237 g_unix_output_stream_new (gint fd,
238 gboolean close_fd)
239 {
240 GUnixOutputStream *stream;
241
242 g_return_val_if_fail (fd != -1, NULL);
243
244 stream = g_object_new (G_TYPE_UNIX_OUTPUT_STREAM,
245 "fd", fd,
246 "close-fd", close_fd,
247 NULL);
248
249 return G_OUTPUT_STREAM (stream);
250 }
251
252 /**
253 * g_unix_output_stream_set_close_fd:
254 * @stream: a #GUnixOutputStream
255 * @close_fd: %TRUE to close the file descriptor when done
256 *
257 * Sets whether the file descriptor of @stream shall be closed
258 * when the stream is closed.
259 *
260 * Since: 2.20
261 */
262 void
263 g_unix_output_stream_set_close_fd (GUnixOutputStream *stream,
264 gboolean close_fd)
265 {
266 g_return_if_fail (G_IS_UNIX_OUTPUT_STREAM (stream));
267
268 close_fd = close_fd != FALSE;
269 if (stream->priv->close_fd != close_fd)
270 {
271 stream->priv->close_fd = close_fd;
272 g_object_notify (G_OBJECT (stream), "close-fd");
273 }
274 }
275
276 /**
277 * g_unix_output_stream_get_close_fd:
278 * @stream: a #GUnixOutputStream
279 *
280 * Returns whether the file descriptor of @stream will be
281 * closed when the stream is closed.
282 *
283 * Returns: %TRUE if the file descriptor is closed when done
284 *
285 * Since: 2.20
286 */
287 gboolean
288 g_unix_output_stream_get_close_fd (GUnixOutputStream *stream)
289 {
290 g_return_val_if_fail (G_IS_UNIX_OUTPUT_STREAM (stream), FALSE);
291
292 return stream->priv->close_fd;
293 }
294
295 /**
296 * g_unix_output_stream_get_fd:
297 * @stream: a #GUnixOutputStream
298 *
299 * Return the UNIX file descriptor that the stream writes to.
300 *
301 * Returns: The file descriptor of @stream
302 *
303 * Since: 2.20
304 */
305 gint
306 g_unix_output_stream_get_fd (GUnixOutputStream *stream)
307 {
308 g_return_val_if_fail (G_IS_UNIX_OUTPUT_STREAM (stream), -1);
309
310 return stream->priv->fd;
311 }
312
313 static gssize
314 g_unix_output_stream_write (GOutputStream *stream,
315 const void *buffer,
316 gsize count,
317 GCancellable *cancellable,
318 GError **error)
319 {
320 GUnixOutputStream *unix_stream;
321 gssize res = -1;
322 GPollFD poll_fds[2];
323 int nfds = 0;
324 int poll_ret;
325
326 unix_stream = G_UNIX_OUTPUT_STREAM (stream);
327
328 poll_fds[0].fd = unix_stream->priv->fd;
329 poll_fds[0].events = G_IO_OUT;
330 nfds++;
331
332 if (unix_stream->priv->can_poll &&
333 g_cancellable_make_pollfd (cancellable, &poll_fds[1]))
334 nfds++;
335
336 while (1)
337 {
338 int errsv;
339
340 poll_fds[0].revents = poll_fds[1].revents = 0;
341 do
342 {
343 poll_ret = g_poll (poll_fds, nfds, -1);
344 errsv = errno;
345 }
346 while (poll_ret == -1 && errsv == EINTR);
347
348 if (poll_ret == -1)
349 {
350 g_set_error (error, G_IO_ERROR,
351 g_io_error_from_errno (errsv),
352 _("Error writing to file descriptor: %s"),
353 g_strerror (errsv));
354 break;
355 }
356
357 if (g_cancellable_set_error_if_cancelled (cancellable, error))
358 break;
359
360 if (!poll_fds[0].revents)
361 continue;
362
363 res = write (unix_stream->priv->fd, buffer, count);
364 errsv = errno;
365 if (res == -1)
366 {
367 if (errsv == EINTR || errsv == EAGAIN)
368 continue;
369
370 g_set_error (error, G_IO_ERROR,
371 g_io_error_from_errno (errsv),
372 _("Error writing to file descriptor: %s"),
373 g_strerror (errsv));
374 }
375
376 break;
377 }
378
379 if (nfds == 2)
380 g_cancellable_release_fd (cancellable);
381 return res;
382 }
383
384 /* Macro to check if struct iovec and GOutputVector have the same ABI */
385 #define G_OUTPUT_VECTOR_IS_IOVEC (sizeof (struct iovec) == sizeof (GOutputVector) && \
386 G_SIZEOF_MEMBER (struct iovec, iov_base) == G_SIZEOF_MEMBER (GOutputVector, buffer) && \
387 G_STRUCT_OFFSET (struct iovec, iov_base) == G_STRUCT_OFFSET (GOutputVector, buffer) && \
388 G_SIZEOF_MEMBER (struct iovec, iov_len) == G_SIZEOF_MEMBER (GOutputVector, size) && \
389 G_STRUCT_OFFSET (struct iovec, iov_len) == G_STRUCT_OFFSET (GOutputVector, size))
390
391 static gboolean
392 g_unix_output_stream_writev (GOutputStream *stream,
393 const GOutputVector *vectors,
394 gsize n_vectors,
395 gsize *bytes_written,
396 GCancellable *cancellable,
397 GError **error)
398 {
399 GUnixOutputStream *unix_stream;
400 gssize res = -1;
401 GPollFD poll_fds[2];
402 int nfds = 0;
403 int poll_ret;
404 struct iovec *iov;
405
406 if (bytes_written)
407 *bytes_written = 0;
408
409 /* Clamp the number of vectors if more given than we can write in one go.
410 * The caller has to handle short writes anyway.
411 */
412 if (n_vectors > G_IOV_MAX)
413 n_vectors = G_IOV_MAX;
414
415 unix_stream = G_UNIX_OUTPUT_STREAM (stream);
416
417 if (G_OUTPUT_VECTOR_IS_IOVEC)
418 {
419 /* ABI is compatible */
420 iov = (struct iovec *) vectors;
421 }
422 else
423 {
424 gsize i;
425
426 /* ABI is incompatible */
427 iov = g_newa (struct iovec, n_vectors);
428 for (i = 0; i < n_vectors; i++)
429 {
430 iov[i].iov_base = (void *)vectors[i].buffer;
431 iov[i].iov_len = vectors[i].size;
432 }
433 }
434
435 poll_fds[0].fd = unix_stream->priv->fd;
436 poll_fds[0].events = G_IO_OUT;
437 nfds++;
438
439 if (unix_stream->priv->can_poll &&
440 g_cancellable_make_pollfd (cancellable, &poll_fds[1]))
441 nfds++;
442
443 while (1)
444 {
445 int errsv;
446
447 poll_fds[0].revents = poll_fds[1].revents = 0;
448 do
449 {
450 poll_ret = g_poll (poll_fds, nfds, -1);
451 errsv = errno;
452 }
453 while (poll_ret == -1 && errsv == EINTR);
454
455 if (poll_ret == -1)
456 {
457 g_set_error (error, G_IO_ERROR,
458 g_io_error_from_errno (errsv),
459 _("Error writing to file descriptor: %s"),
460 g_strerror (errsv));
461 break;
462 }
463
464 if (g_cancellable_set_error_if_cancelled (cancellable, error))
465 break;
466
467 if (!poll_fds[0].revents)
468 continue;
469
470 res = writev (unix_stream->priv->fd, iov, n_vectors);
471 errsv = errno;
472 if (res == -1)
473 {
474 if (errsv == EINTR || errsv == EAGAIN)
475 continue;
476
477 g_set_error (error, G_IO_ERROR,
478 g_io_error_from_errno (errsv),
479 _("Error writing to file descriptor: %s"),
480 g_strerror (errsv));
481 }
482
483 if (bytes_written)
484 *bytes_written = res;
485
486 break;
487 }
488
489 if (nfds == 2)
490 g_cancellable_release_fd (cancellable);
491 return res != -1;
492 }
493
494 static gboolean
495 g_unix_output_stream_close (GOutputStream *stream,
496 GCancellable *cancellable,
497 GError **error)
498 {
499 GUnixOutputStream *unix_stream;
500 int res;
501
502 unix_stream = G_UNIX_OUTPUT_STREAM (stream);
503
504 if (!unix_stream->priv->close_fd)
505 return TRUE;
506
507 /* This might block during the close. Doesn't seem to be a way to avoid it though. */
508 res = close (unix_stream->priv->fd);
509 if (res == -1)
510 {
511 int errsv = errno;
512
513 g_set_error (error, G_IO_ERROR,
514 g_io_error_from_errno (errsv),
515 _("Error closing file descriptor: %s"),
516 g_strerror (errsv));
517 }
518
519 return res != -1;
520 }
521
522 static gboolean
523 g_unix_output_stream_pollable_can_poll (GPollableOutputStream *stream)
524 {
525 return G_UNIX_OUTPUT_STREAM (stream)->priv->can_poll;
526 }
527
528 static gboolean
529 g_unix_output_stream_pollable_is_writable (GPollableOutputStream *stream)
530 {
531 GUnixOutputStream *unix_stream = G_UNIX_OUTPUT_STREAM (stream);
532 GPollFD poll_fd;
533 gint result;
534
535 poll_fd.fd = unix_stream->priv->fd;
536 poll_fd.events = G_IO_OUT;
537 poll_fd.revents = 0;
538
539 do
540 result = g_poll (&poll_fd, 1, 0);
541 while (result == -1 && errno == EINTR);
542
543 return poll_fd.revents != 0;
544 }
545
546 static GSource *
547 g_unix_output_stream_pollable_create_source (GPollableOutputStream *stream,
548 GCancellable *cancellable)
549 {
550 GUnixOutputStream *unix_stream = G_UNIX_OUTPUT_STREAM (stream);
551 GSource *inner_source, *cancellable_source, *pollable_source;
552
553 pollable_source = g_pollable_source_new (G_OBJECT (stream));
554
555 inner_source = g_unix_fd_source_new (unix_stream->priv->fd, G_IO_OUT);
556 g_source_set_dummy_callback (inner_source);
557 g_source_add_child_source (pollable_source, inner_source);
558 g_source_unref (inner_source);
559
560 if (cancellable)
561 {
562 cancellable_source = g_cancellable_source_new (cancellable);
563 g_source_set_dummy_callback (cancellable_source);
564 g_source_add_child_source (pollable_source, cancellable_source);
565 g_source_unref (cancellable_source);
566 }
567
568 return pollable_source;
569 }
570
571 static GPollableReturn
572 g_unix_output_stream_pollable_writev_nonblocking (GPollableOutputStream *stream,
573 const GOutputVector *vectors,
574 gsize n_vectors,
575 gsize *bytes_written,
576 GError **error)
577 {
578 GUnixOutputStream *unix_stream = G_UNIX_OUTPUT_STREAM (stream);
579 struct iovec *iov;
580 gssize res = -1;
581
582 if (!g_pollable_output_stream_is_writable (stream))
583 {
584 *bytes_written = 0;
585 return G_POLLABLE_RETURN_WOULD_BLOCK;
586 }
587
588 /* Clamp the number of vectors if more given than we can write in one go.
589 * The caller has to handle short writes anyway.
590 */
591 if (n_vectors > G_IOV_MAX)
592 n_vectors = G_IOV_MAX;
593
594 if (G_OUTPUT_VECTOR_IS_IOVEC)
595 {
596 /* ABI is compatible */
597 iov = (struct iovec *) vectors;
598 }
599 else
600 {
601 gsize i;
602
603 /* ABI is incompatible */
604 iov = g_newa (struct iovec, n_vectors);
605 for (i = 0; i < n_vectors; i++)
606 {
607 iov[i].iov_base = (void *)vectors[i].buffer;
608 iov[i].iov_len = vectors[i].size;
609 }
610 }
611
612 while (1)
613 {
614 int errsv;
615
616 res = writev (unix_stream->priv->fd, iov, n_vectors);
617 errsv = errno;
618 if (res == -1)
619 {
620 if (errsv == EINTR)
621 continue;
622
623 g_set_error (error, G_IO_ERROR,
624 g_io_error_from_errno (errsv),
625 _("Error writing to file descriptor: %s"),
626 g_strerror (errsv));
627 }
628
629 if (bytes_written)
630 *bytes_written = res;
631
632 break;
633 }
634
635 return res != -1 ? G_POLLABLE_RETURN_OK : G_POLLABLE_RETURN_FAILED;
636 }