Bug 591714 – Figure out failure handling for g_cancellable_make_pollfd()
[platform/upstream/glib.git] / gio / gunixinputstream.c
1 /* GIO - GLib Input, Output and Streaming Library
2  * 
3  * Copyright (C) 2006-2007 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 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, write to the
17  * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
18  * Boston, MA 02111-1307, USA.
19  *
20  * Author: Alexander Larsson <alexl@redhat.com>
21  */
22
23 #include "config.h"
24
25 #include <sys/types.h>
26 #include <sys/stat.h>
27 #include <unistd.h>
28 #include <errno.h>
29 #include <stdio.h>
30 #include <fcntl.h>
31
32 #include <glib.h>
33 #include <glib/gstdio.h>
34 #include "gioerror.h"
35 #include "gsimpleasyncresult.h"
36 #include "gunixinputstream.h"
37 #include "gcancellable.h"
38 #include "gasynchelper.h"
39 #include "glibintl.h"
40
41 #include "gioalias.h"
42
43 /**
44  * SECTION:gunixinputstream
45  * @short_description: Streaming input operations for UNIX file descriptors
46  * @include: gio/gunixinputstream.h
47  * @see_also: #GInputStream
48  *
49  * #GUnixInputStream implements #GInputStream for reading from a
50  * UNIX file descriptor, including asynchronous operations. The file
51  * descriptor must be selectable, so it doesn't work with opened files.
52  *
53  * Note that <filename>&lt;gio/gunixinputstream.h&gt;</filename> belongs 
54  * to the UNIX-specific GIO interfaces, thus you have to use the 
55  * <filename>gio-unix-2.0.pc</filename> pkg-config file when using it.
56  */
57
58 enum {
59   PROP_0,
60   PROP_FD,
61   PROP_CLOSE_FD
62 };
63
64 G_DEFINE_TYPE (GUnixInputStream, g_unix_input_stream, G_TYPE_INPUT_STREAM);
65
66 struct _GUnixInputStreamPrivate {
67   int fd;
68   gboolean close_fd;
69 };
70
71 static void     g_unix_input_stream_set_property (GObject              *object,
72                                                   guint                 prop_id,
73                                                   const GValue         *value,
74                                                   GParamSpec           *pspec);
75 static void     g_unix_input_stream_get_property (GObject              *object,
76                                                   guint                 prop_id,
77                                                   GValue               *value,
78                                                   GParamSpec           *pspec);
79 static gssize   g_unix_input_stream_read         (GInputStream         *stream,
80                                                   void                 *buffer,
81                                                   gsize                 count,
82                                                   GCancellable         *cancellable,
83                                                   GError              **error);
84 static gboolean g_unix_input_stream_close        (GInputStream         *stream,
85                                                   GCancellable         *cancellable,
86                                                   GError              **error);
87 static void     g_unix_input_stream_read_async   (GInputStream         *stream,
88                                                   void                 *buffer,
89                                                   gsize                 count,
90                                                   int                   io_priority,
91                                                   GCancellable         *cancellable,
92                                                   GAsyncReadyCallback   callback,
93                                                   gpointer              data);
94 static gssize   g_unix_input_stream_read_finish  (GInputStream         *stream,
95                                                   GAsyncResult         *result,
96                                                   GError              **error);
97 static void     g_unix_input_stream_skip_async   (GInputStream         *stream,
98                                                   gsize                 count,
99                                                   int                   io_priority,
100                                                   GCancellable         *cancellable,
101                                                   GAsyncReadyCallback   callback,
102                                                   gpointer              data);
103 static gssize   g_unix_input_stream_skip_finish  (GInputStream         *stream,
104                                                   GAsyncResult         *result,
105                                                   GError              **error);
106 static void     g_unix_input_stream_close_async  (GInputStream         *stream,
107                                                   int                   io_priority,
108                                                   GCancellable         *cancellable,
109                                                   GAsyncReadyCallback   callback,
110                                                   gpointer              data);
111 static gboolean g_unix_input_stream_close_finish (GInputStream         *stream,
112                                                   GAsyncResult         *result,
113                                                   GError              **error);
114
115
116 static void
117 g_unix_input_stream_finalize (GObject *object)
118 {
119   GUnixInputStream *stream;
120   
121   stream = G_UNIX_INPUT_STREAM (object);
122
123   G_OBJECT_CLASS (g_unix_input_stream_parent_class)->finalize (object);
124 }
125
126 static void
127 g_unix_input_stream_class_init (GUnixInputStreamClass *klass)
128 {
129   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
130   GInputStreamClass *stream_class = G_INPUT_STREAM_CLASS (klass);
131   
132   g_type_class_add_private (klass, sizeof (GUnixInputStreamPrivate));
133
134   gobject_class->get_property = g_unix_input_stream_get_property;
135   gobject_class->set_property = g_unix_input_stream_set_property;
136   gobject_class->finalize = g_unix_input_stream_finalize;
137
138   stream_class->read_fn = g_unix_input_stream_read;
139   stream_class->close_fn = g_unix_input_stream_close;
140   stream_class->read_async = g_unix_input_stream_read_async;
141   stream_class->read_finish = g_unix_input_stream_read_finish;
142   if (0)
143     {
144       /* TODO: Implement instead of using fallbacks */
145       stream_class->skip_async = g_unix_input_stream_skip_async;
146       stream_class->skip_finish = g_unix_input_stream_skip_finish;
147     }
148   stream_class->close_async = g_unix_input_stream_close_async;
149   stream_class->close_finish = g_unix_input_stream_close_finish;
150
151   /**
152    * GUnixInputStream:fd:
153    *
154    * The file descriptor that the stream reads from.
155    *
156    * Since: 2.20
157    */
158   g_object_class_install_property (gobject_class,
159                                    PROP_FD,
160                                    g_param_spec_int ("fd",
161                                                      P_("File descriptor"),
162                                                      P_("The file descriptor to read from"),
163                                                      G_MININT, G_MAXINT, -1,
164                                                      G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
165
166   /**
167    * GUnixInputStream:close-fd:
168    *
169    * Whether to close the file descriptor when the stream is closed.
170    *
171    * Since: 2.20
172    */
173   g_object_class_install_property (gobject_class,
174                                    PROP_CLOSE_FD,
175                                    g_param_spec_boolean ("close-fd",
176                                                          P_("Close file descriptor"),
177                                                          P_("Whether to close the file descriptor when the stream is closed"),
178                                                          TRUE,
179                                                          G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
180 }
181
182 static void
183 g_unix_input_stream_set_property (GObject         *object,
184                                   guint            prop_id,
185                                   const GValue    *value,
186                                   GParamSpec      *pspec)
187 {
188   GUnixInputStream *unix_stream;
189   
190   unix_stream = G_UNIX_INPUT_STREAM (object);
191
192   switch (prop_id)
193     {
194     case PROP_FD:
195       unix_stream->priv->fd = g_value_get_int (value);
196       break;
197     case PROP_CLOSE_FD:
198       unix_stream->priv->close_fd = g_value_get_boolean (value);
199       break;
200     default:
201       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
202       break;
203     }
204 }
205
206 static void
207 g_unix_input_stream_get_property (GObject    *object,
208                                   guint       prop_id,
209                                   GValue     *value,
210                                   GParamSpec *pspec)
211 {
212   GUnixInputStream *unix_stream;
213
214   unix_stream = G_UNIX_INPUT_STREAM (object);
215
216   switch (prop_id)
217     {
218     case PROP_FD:
219       g_value_set_int (value, unix_stream->priv->fd);
220       break;
221     case PROP_CLOSE_FD:
222       g_value_set_boolean (value, unix_stream->priv->close_fd);
223       break;
224     default:
225       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
226     }
227 }
228
229 static void
230 g_unix_input_stream_init (GUnixInputStream *unix_stream)
231 {
232   unix_stream->priv = G_TYPE_INSTANCE_GET_PRIVATE (unix_stream,
233                                                    G_TYPE_UNIX_INPUT_STREAM,
234                                                    GUnixInputStreamPrivate);
235
236   unix_stream->priv->fd = -1;
237   unix_stream->priv->close_fd = TRUE;
238 }
239
240 /**
241  * g_unix_input_stream_new:
242  * @fd: a UNIX file descriptor
243  * @close_fd: %TRUE to close the file descriptor when done
244  * 
245  * Creates a new #GUnixInputStream for the given @fd. 
246  *
247  * If @close_fd is %TRUE, the file descriptor will be closed 
248  * when the stream is closed.
249  * 
250  * Returns: a new #GUnixInputStream
251  **/
252 GInputStream *
253 g_unix_input_stream_new (gint     fd,
254                          gboolean close_fd)
255 {
256   GUnixInputStream *stream;
257
258   g_return_val_if_fail (fd != -1, NULL);
259
260   stream = g_object_new (G_TYPE_UNIX_INPUT_STREAM,
261                          "fd", fd,
262                          "close-fd", close_fd,
263                          NULL);
264
265   return G_INPUT_STREAM (stream);
266 }
267
268 /**
269  * g_unix_input_stream_set_close_fd:
270  * @stream: a #GUnixInputStream
271  * @close_fd: %TRUE to close the file descriptor when done
272  *
273  * Sets whether the file descriptor of @stream shall be closed
274  * when the stream is closed.
275  *
276  * Since: 2.20
277  */
278 void
279 g_unix_input_stream_set_close_fd (GUnixInputStream *stream,
280                                   gboolean          close_fd)
281 {
282   g_return_if_fail (G_IS_UNIX_INPUT_STREAM (stream));
283
284   close_fd = close_fd != FALSE;
285   if (stream->priv->close_fd != close_fd)
286     {
287       stream->priv->close_fd = close_fd;
288       g_object_notify (G_OBJECT (stream), "close-fd");
289     }
290 }
291
292 /**
293  * g_unix_input_stream_get_close_fd:
294  * @stream: a #GUnixInputStream
295  *
296  * Returns whether the file descriptor of @stream will be
297  * closed when the stream is closed.
298  *
299  * Return value: %TRUE if the file descriptor is closed when done
300  *
301  * Since: 2.20
302  */
303 gboolean
304 g_unix_input_stream_get_close_fd (GUnixInputStream *stream)
305 {
306   g_return_val_if_fail (G_IS_UNIX_INPUT_STREAM (stream), FALSE);
307
308   return stream->priv->close_fd;
309 }
310
311 /**
312  * g_unix_input_stream_get_fd:
313  * @stream: a #GUnixInputStream
314  *
315  * Return the UNIX file descriptor that the stream reads from.
316  *
317  * Return value: The file descriptor of @stream
318  *
319  * Since: 2.20
320  */
321 gint
322 g_unix_input_stream_get_fd (GUnixInputStream *stream)
323 {
324   g_return_val_if_fail (G_IS_UNIX_INPUT_STREAM (stream), -1);
325   
326   return stream->priv->fd;
327 }
328
329 static gssize
330 g_unix_input_stream_read (GInputStream  *stream,
331                           void          *buffer,
332                           gsize          count,
333                           GCancellable  *cancellable,
334                           GError       **error)
335 {
336   GUnixInputStream *unix_stream;
337   gssize res;
338   GPollFD poll_fds[2];
339   int poll_ret;
340
341   unix_stream = G_UNIX_INPUT_STREAM (stream);
342
343   if (g_cancellable_make_pollfd (cancellable, &poll_fds[1]))
344     {
345       poll_fds[0].fd = unix_stream->priv->fd;
346       poll_fds[0].events = G_IO_IN;
347       do
348         poll_ret = g_poll (poll_fds, 2, -1);
349       while (poll_ret == -1 && errno == EINTR);
350       
351       if (poll_ret == -1)
352         {
353           int errsv = errno;
354
355           g_set_error (error, G_IO_ERROR,
356                        g_io_error_from_errno (errsv),
357                        _("Error reading from unix: %s"),
358                        g_strerror (errsv));
359           return -1;
360         }
361     }
362
363   while (1)
364     {
365       if (g_cancellable_set_error_if_cancelled (cancellable, error))
366         return -1;
367       res = read (unix_stream->priv->fd, buffer, count);
368       if (res == -1)
369         {
370           int errsv = errno;
371
372           if (errsv == EINTR)
373             continue;
374           
375           g_set_error (error, G_IO_ERROR,
376                        g_io_error_from_errno (errsv),
377                        _("Error reading from unix: %s"),
378                        g_strerror (errsv));
379         }
380       
381       break;
382     }
383
384   return res;
385 }
386
387 static gboolean
388 g_unix_input_stream_close (GInputStream  *stream,
389                            GCancellable  *cancellable,
390                            GError       **error)
391 {
392   GUnixInputStream *unix_stream;
393   int res;
394
395   unix_stream = G_UNIX_INPUT_STREAM (stream);
396
397   if (!unix_stream->priv->close_fd)
398     return TRUE;
399   
400   while (1)
401     {
402       /* This might block during the close. Doesn't seem to be a way to avoid it though. */
403       res = close (unix_stream->priv->fd);
404       if (res == -1)
405         {
406           int errsv = errno;
407
408           g_set_error (error, G_IO_ERROR,
409                        g_io_error_from_errno (errsv),
410                        _("Error closing unix: %s"),
411                        g_strerror (errsv));
412         }
413       break;
414     }
415   
416   return res != -1;
417 }
418
419 typedef struct {
420   gsize count;
421   void *buffer;
422   GAsyncReadyCallback callback;
423   gpointer user_data;
424   GCancellable *cancellable;
425   GUnixInputStream *stream;
426 } ReadAsyncData;
427
428 static gboolean
429 read_async_cb (ReadAsyncData *data,
430                GIOCondition   condition,
431                int            fd)
432 {
433   GSimpleAsyncResult *simple;
434   GError *error = NULL;
435   gssize count_read;
436
437   /* We know that we can read from fd once without blocking */
438   while (1)
439     {
440       if (g_cancellable_set_error_if_cancelled (data->cancellable, &error))
441         {
442           count_read = -1;
443           break;
444         }
445       count_read = read (data->stream->priv->fd, data->buffer, data->count);
446       if (count_read == -1)
447         {
448           int errsv = errno;
449
450           if (errsv == EINTR)
451             continue;
452           
453           g_set_error (&error, G_IO_ERROR,
454                        g_io_error_from_errno (errsv),
455                        _("Error reading from unix: %s"),
456                        g_strerror (errsv));
457         }
458       break;
459     }
460
461   simple = g_simple_async_result_new (G_OBJECT (data->stream),
462                                       data->callback,
463                                       data->user_data,
464                                       g_unix_input_stream_read_async);
465
466   g_simple_async_result_set_op_res_gssize (simple, count_read);
467
468   if (count_read == -1)
469     {
470       g_simple_async_result_set_from_error (simple, error);
471       g_error_free (error);
472     }
473
474   /* Complete immediately, not in idle, since we're already in a mainloop callout */
475   g_simple_async_result_complete (simple);
476   g_object_unref (simple);
477
478   return FALSE;
479 }
480
481 static void
482 g_unix_input_stream_read_async (GInputStream        *stream,
483                                 void                *buffer,
484                                 gsize                count,
485                                 int                  io_priority,
486                                 GCancellable        *cancellable,
487                                 GAsyncReadyCallback  callback,
488                                 gpointer             user_data)
489 {
490   GSource *source;
491   GUnixInputStream *unix_stream;
492   ReadAsyncData *data;
493
494   unix_stream = G_UNIX_INPUT_STREAM (stream);
495
496   data = g_new0 (ReadAsyncData, 1);
497   data->count = count;
498   data->buffer = buffer;
499   data->callback = callback;
500   data->user_data = user_data;
501   data->cancellable = cancellable;
502   data->stream = unix_stream;
503
504   source = _g_fd_source_new (unix_stream->priv->fd,
505                              G_IO_IN,
506                              cancellable);
507   
508   g_source_set_callback (source, (GSourceFunc)read_async_cb, data, g_free);
509   g_source_attach (source, g_main_context_get_thread_default ());
510  
511   g_source_unref (source);
512 }
513
514 static gssize
515 g_unix_input_stream_read_finish (GInputStream  *stream,
516                                  GAsyncResult  *result,
517                                  GError       **error)
518 {
519   GSimpleAsyncResult *simple;
520   gssize nread;
521
522   simple = G_SIMPLE_ASYNC_RESULT (result);
523   g_warn_if_fail (g_simple_async_result_get_source_tag (simple) == g_unix_input_stream_read_async);
524   
525   nread = g_simple_async_result_get_op_res_gssize (simple);
526   return nread;
527 }
528
529 static void
530 g_unix_input_stream_skip_async (GInputStream        *stream,
531                                 gsize                count,
532                                 int                  io_priority,
533                                 GCancellable        *cancellable,
534                                 GAsyncReadyCallback  callback,
535                                 gpointer             data)
536 {
537   g_warn_if_reached ();
538   /* TODO: Not implemented */
539 }
540
541 static gssize
542 g_unix_input_stream_skip_finish  (GInputStream  *stream,
543                                   GAsyncResult  *result,
544                                   GError       **error)
545 {
546   g_warn_if_reached ();
547   return 0;
548   /* TODO: Not implemented */
549 }
550
551
552 typedef struct {
553   GInputStream *stream;
554   GAsyncReadyCallback callback;
555   gpointer user_data;
556 } CloseAsyncData;
557
558 static void
559 close_async_data_free (gpointer _data)
560 {
561   CloseAsyncData *data = _data;
562
563   g_free (data);
564 }
565
566 static gboolean
567 close_async_cb (CloseAsyncData *data)
568 {
569   GUnixInputStream *unix_stream;
570   GSimpleAsyncResult *simple;
571   GError *error = NULL;
572   gboolean result;
573   int res;
574
575   unix_stream = G_UNIX_INPUT_STREAM (data->stream);
576
577   if (!unix_stream->priv->close_fd)
578     {
579       result = TRUE;
580       goto out;
581     }
582   
583   while (1)
584     {
585       res = close (unix_stream->priv->fd);
586       if (res == -1)
587         {
588           int errsv = errno;
589
590           g_set_error (&error, G_IO_ERROR,
591                        g_io_error_from_errno (errsv),
592                        _("Error closing unix: %s"),
593                        g_strerror (errsv));
594         }
595       break;
596     }
597   
598   result = res != -1;
599
600  out:
601   simple = g_simple_async_result_new (G_OBJECT (data->stream),
602                                       data->callback,
603                                       data->user_data,
604                                       g_unix_input_stream_close_async);
605
606   if (!result)
607     {
608       g_simple_async_result_set_from_error (simple, error);
609       g_error_free (error);
610     }
611
612   /* Complete immediately, not in idle, since we're already in a mainloop callout */
613   g_simple_async_result_complete (simple);
614   g_object_unref (simple);
615   
616   return FALSE;
617 }
618
619 static void
620 g_unix_input_stream_close_async (GInputStream        *stream,
621                                  int                  io_priority,
622                                  GCancellable        *cancellable,
623                                  GAsyncReadyCallback  callback,
624                                  gpointer             user_data)
625 {
626   GSource *idle;
627   CloseAsyncData *data;
628
629   data = g_new0 (CloseAsyncData, 1);
630
631   data->stream = stream;
632   data->callback = callback;
633   data->user_data = user_data;
634   
635   idle = g_idle_source_new ();
636   g_source_set_callback (idle, (GSourceFunc)close_async_cb, data, close_async_data_free);
637   g_source_attach (idle, g_main_context_get_thread_default ());
638   g_source_unref (idle);
639 }
640
641 static gboolean
642 g_unix_input_stream_close_finish (GInputStream  *stream,
643                                   GAsyncResult  *result,
644                                   GError       **error)
645 {
646   /* Failures handled in generic close_finish code */
647   return TRUE;
648 }
649
650 #define __G_UNIX_INPUT_STREAM_C__
651 #include "gioaliasdef.c"