Revert "Unref GCancellables if they were reffed by the object."
[platform/upstream/glib-networking.git] / tls / gnutls / gtlsinputstream-gnutls.c
1 /* GIO - GLib Input, Output and Streaming Library
2  *
3  * Copyright © 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 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
21 #include "config.h"
22 #include "gtlsinputstream-gnutls.h"
23
24 static void g_tls_input_stream_gnutls_pollable_iface_init (GPollableInputStreamInterface *iface);
25
26 G_DEFINE_TYPE_WITH_CODE (GTlsInputStreamGnutls, g_tls_input_stream_gnutls, G_TYPE_INPUT_STREAM,
27                          G_IMPLEMENT_INTERFACE (G_TYPE_POLLABLE_INPUT_STREAM, g_tls_input_stream_gnutls_pollable_iface_init)
28                          )
29
30 struct _GTlsInputStreamGnutlsPrivate
31 {
32   GTlsConnectionGnutls *conn;
33
34   /* pending operation metadata */
35   GCancellable *cancellable;
36   gpointer buffer;
37   gsize count;
38 };
39
40 static void
41 g_tls_input_stream_gnutls_finalize (GObject *object)
42 {
43   GTlsInputStreamGnutls *stream = G_TLS_INPUT_STREAM_GNUTLS (object);
44
45   if (stream->priv->conn)
46     g_object_unref (stream->priv->conn);
47
48   G_OBJECT_CLASS (g_tls_input_stream_gnutls_parent_class)->finalize (object);
49 }
50
51 static gssize
52 g_tls_input_stream_gnutls_read (GInputStream  *stream,
53                                 void          *buffer,
54                                 gsize          count,
55                                 GCancellable  *cancellable,
56                                 GError       **error)
57 {
58   GTlsInputStreamGnutls *tls_stream = G_TLS_INPUT_STREAM_GNUTLS (stream);
59
60   return g_tls_connection_gnutls_read (tls_stream->priv->conn,
61                                        buffer, count, TRUE,
62                                        cancellable, error);
63 }
64
65 static gboolean
66 g_tls_input_stream_gnutls_read_ready (GPollableInputStream *stream,
67                                       gpointer              user_data)
68 {
69   GTlsInputStreamGnutls *tls_stream;
70   GSimpleAsyncResult *simple = user_data;
71   gssize nread;
72   GError *error = NULL;
73
74   tls_stream = G_TLS_INPUT_STREAM_GNUTLS (g_async_result_get_source_object (G_ASYNC_RESULT (simple)));
75   g_object_unref (tls_stream);
76
77   nread = g_tls_connection_gnutls_read (tls_stream->priv->conn,
78                                         tls_stream->priv->buffer,
79                                         tls_stream->priv->count, FALSE,
80                                         tls_stream->priv->cancellable,
81                                         &error);
82   if (nread == -1 &&
83       g_error_matches (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK))
84     {
85       g_error_free (error);
86       return TRUE;
87     }
88
89   if (error)
90     {
91       g_simple_async_result_set_from_error (simple, error);
92       g_error_free (error);
93     }
94   else
95     g_simple_async_result_set_op_res_gssize (simple, nread);
96   g_simple_async_result_complete (simple);
97   g_object_unref (simple);
98
99   return FALSE;
100 }
101
102 static void
103 g_tls_input_stream_gnutls_read_async (GInputStream        *stream,
104                                       void                *buffer,
105                                       gsize                count,
106                                       gint                 io_priority,
107                                       GCancellable        *cancellable,
108                                       GAsyncReadyCallback  callback,
109                                       gpointer             user_data)
110 {
111   GTlsInputStreamGnutls *tls_stream = G_TLS_INPUT_STREAM_GNUTLS (stream);
112   GSimpleAsyncResult *simple;
113   gssize nread;
114   GError *error = NULL;
115   GSource *source;
116
117   simple = g_simple_async_result_new (G_OBJECT (stream), callback, user_data,
118                                       g_tls_input_stream_gnutls_read_async);
119   nread = g_tls_connection_gnutls_read (tls_stream->priv->conn,
120                                         buffer, count, FALSE,
121                                         cancellable, &error);
122
123   if (nread >= 0 ||
124       !g_error_matches (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK))
125     {
126       if (error)
127         {
128           g_simple_async_result_set_from_error (simple, error);
129           g_error_free (error);
130         }
131       else
132         g_simple_async_result_set_op_res_gssize (simple, nread);
133       g_simple_async_result_complete_in_idle (simple);
134       g_object_unref (simple);
135       return;
136     }
137
138   tls_stream->priv->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
139   tls_stream->priv->buffer = buffer;
140   tls_stream->priv->count = count;
141
142   source = g_tls_connection_gnutls_create_source (tls_stream->priv->conn,
143                                                   G_IO_IN,
144                                                   tls_stream->priv->cancellable);
145   g_source_set_callback (source,
146                          (GSourceFunc) g_tls_input_stream_gnutls_read_ready,
147                          simple, NULL);
148   g_source_attach (source, g_main_context_get_thread_default ());
149   g_source_unref (source);
150 }
151
152 static gssize
153 g_tls_input_stream_gnutls_read_finish (GInputStream  *stream,
154                                        GAsyncResult  *result,
155                                        GError       **error)
156 {
157   g_return_val_if_fail (G_IS_TLS_INPUT_STREAM_GNUTLS (stream), -1);
158   g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (stream), g_tls_input_stream_gnutls_read_async), -1);
159
160   return g_simple_async_result_get_op_res_gssize (G_SIMPLE_ASYNC_RESULT (result));
161 }
162
163 static gboolean
164 g_tls_input_stream_gnutls_pollable_is_readable (GPollableInputStream *pollable)
165 {
166   GTlsInputStreamGnutls *tls_stream = G_TLS_INPUT_STREAM_GNUTLS (pollable);
167
168   return g_tls_connection_gnutls_check (tls_stream->priv->conn, G_IO_IN); 
169 }
170
171 static GSource *
172 g_tls_input_stream_gnutls_pollable_create_source (GPollableInputStream *pollable,
173                                                   GCancellable         *cancellable)
174 {
175   GTlsInputStreamGnutls *tls_stream = G_TLS_INPUT_STREAM_GNUTLS (pollable);
176
177   return g_tls_connection_gnutls_create_source (tls_stream->priv->conn,
178                                                 G_IO_IN,
179                                                 cancellable);
180 }
181
182 static gssize
183 g_tls_input_stream_gnutls_pollable_read_nonblocking (GPollableInputStream  *pollable,
184                                                      void                  *buffer,
185                                                      gsize                  size,
186                                                      GError               **error)
187 {
188   GTlsInputStreamGnutls *tls_stream = G_TLS_INPUT_STREAM_GNUTLS (pollable);
189
190   return g_tls_connection_gnutls_read (tls_stream->priv->conn,
191                                        buffer, size, FALSE,
192                                        NULL, error);
193 }
194
195 static void
196 g_tls_input_stream_gnutls_class_init (GTlsInputStreamGnutlsClass *klass)
197 {
198   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
199   GInputStreamClass *input_stream_class = G_INPUT_STREAM_CLASS (klass);
200
201   g_type_class_add_private (klass, sizeof (GTlsInputStreamGnutlsPrivate));
202
203   gobject_class->finalize = g_tls_input_stream_gnutls_finalize;
204
205   input_stream_class->read_fn = g_tls_input_stream_gnutls_read;
206   input_stream_class->read_async = g_tls_input_stream_gnutls_read_async;
207   input_stream_class->read_finish = g_tls_input_stream_gnutls_read_finish;
208 }
209
210 static void
211 g_tls_input_stream_gnutls_pollable_iface_init (GPollableInputStreamInterface *iface)
212 {
213   iface->is_readable = g_tls_input_stream_gnutls_pollable_is_readable;
214   iface->create_source = g_tls_input_stream_gnutls_pollable_create_source;
215   iface->read_nonblocking = g_tls_input_stream_gnutls_pollable_read_nonblocking;
216 }
217
218 static void
219 g_tls_input_stream_gnutls_init (GTlsInputStreamGnutls *stream)
220 {
221   stream->priv = G_TYPE_INSTANCE_GET_PRIVATE (stream, G_TYPE_TLS_INPUT_STREAM_GNUTLS, GTlsInputStreamGnutlsPrivate);
222 }
223
224 GInputStream *
225 g_tls_input_stream_gnutls_new (GTlsConnectionGnutls *conn)
226 {
227   GTlsInputStreamGnutls *tls_stream;
228
229   tls_stream = g_object_new (G_TYPE_TLS_INPUT_STREAM_GNUTLS, NULL);
230   tls_stream->priv->conn = g_object_ref (conn);
231   return G_INPUT_STREAM (tls_stream);
232 }