gnutls: rearrange some code to avoid a warning
[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_dispose (GObject *object)
42 {
43   GTlsInputStreamGnutls *stream = G_TLS_INPUT_STREAM_GNUTLS (object);
44
45   if (stream->priv->conn)
46     {
47       g_object_remove_weak_pointer (G_OBJECT (stream->priv->conn),
48                                     (gpointer *)&stream->priv->conn);
49       stream->priv->conn = NULL;
50     }
51
52   G_OBJECT_CLASS (g_tls_input_stream_gnutls_parent_class)->dispose (object);
53 }
54
55 static gssize
56 g_tls_input_stream_gnutls_read (GInputStream  *stream,
57                                 void          *buffer,
58                                 gsize          count,
59                                 GCancellable  *cancellable,
60                                 GError       **error)
61 {
62   GTlsInputStreamGnutls *tls_stream = G_TLS_INPUT_STREAM_GNUTLS (stream);
63
64   g_return_val_if_fail (tls_stream->priv->conn != NULL, -1);
65
66   return g_tls_connection_gnutls_read (tls_stream->priv->conn,
67                                        buffer, count, TRUE,
68                                        cancellable, error);
69 }
70
71 static gboolean
72 g_tls_input_stream_gnutls_read_ready (GPollableInputStream *stream,
73                                       gpointer              user_data)
74 {
75   GTlsInputStreamGnutls *tls_stream;
76   GSimpleAsyncResult *simple = user_data;
77   gssize nread;
78   GError *error = NULL;
79
80   tls_stream = G_TLS_INPUT_STREAM_GNUTLS (g_async_result_get_source_object (G_ASYNC_RESULT (simple)));
81   g_object_unref (tls_stream);
82
83   nread = g_tls_connection_gnutls_read (tls_stream->priv->conn,
84                                         tls_stream->priv->buffer,
85                                         tls_stream->priv->count, FALSE,
86                                         tls_stream->priv->cancellable,
87                                         &error);
88   if (nread == -1 &&
89       g_error_matches (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK))
90     {
91       g_error_free (error);
92       return TRUE;
93     }
94
95   if (error)
96     {
97       g_simple_async_result_set_from_error (simple, error);
98       g_error_free (error);
99     }
100   else
101     g_simple_async_result_set_op_res_gssize (simple, nread);
102
103   if (tls_stream->priv->cancellable)
104     g_object_unref (tls_stream->priv->cancellable);
105   g_simple_async_result_complete (simple);
106   g_object_unref (simple);
107
108   return FALSE;
109 }
110
111 static void
112 g_tls_input_stream_gnutls_read_async (GInputStream        *stream,
113                                       void                *buffer,
114                                       gsize                count,
115                                       gint                 io_priority,
116                                       GCancellable        *cancellable,
117                                       GAsyncReadyCallback  callback,
118                                       gpointer             user_data)
119 {
120   GTlsInputStreamGnutls *tls_stream = G_TLS_INPUT_STREAM_GNUTLS (stream);
121   GSimpleAsyncResult *simple;
122   gssize nread;
123   GError *error = NULL;
124   GSource *source;
125
126   g_return_if_fail (tls_stream->priv->conn != NULL);
127
128   simple = g_simple_async_result_new (G_OBJECT (stream), callback, user_data,
129                                       g_tls_input_stream_gnutls_read_async);
130   nread = g_tls_connection_gnutls_read (tls_stream->priv->conn,
131                                         buffer, count, FALSE,
132                                         cancellable, &error);
133
134   if (nread >= 0 ||
135       !g_error_matches (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK))
136     {
137       if (error)
138         {
139           g_simple_async_result_set_from_error (simple, error);
140           g_error_free (error);
141         }
142       else
143         g_simple_async_result_set_op_res_gssize (simple, nread);
144       g_simple_async_result_complete_in_idle (simple);
145       g_object_unref (simple);
146       return;
147     }
148
149   tls_stream->priv->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
150   tls_stream->priv->buffer = buffer;
151   tls_stream->priv->count = count;
152
153   source = g_tls_connection_gnutls_create_source (tls_stream->priv->conn,
154                                                   G_IO_IN,
155                                                   tls_stream->priv->cancellable);
156   g_source_set_callback (source,
157                          (GSourceFunc) g_tls_input_stream_gnutls_read_ready,
158                          simple, NULL);
159   g_source_attach (source, g_main_context_get_thread_default ());
160   g_source_unref (source);
161 }
162
163 static gssize
164 g_tls_input_stream_gnutls_read_finish (GInputStream  *stream,
165                                        GAsyncResult  *result,
166                                        GError       **error)
167 {
168   g_return_val_if_fail (G_IS_TLS_INPUT_STREAM_GNUTLS (stream), -1);
169   g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (stream), g_tls_input_stream_gnutls_read_async), -1);
170
171   return g_simple_async_result_get_op_res_gssize (G_SIMPLE_ASYNC_RESULT (result));
172 }
173
174 static gboolean
175 g_tls_input_stream_gnutls_pollable_is_readable (GPollableInputStream *pollable)
176 {
177   GTlsInputStreamGnutls *tls_stream = G_TLS_INPUT_STREAM_GNUTLS (pollable);
178
179   g_return_val_if_fail (tls_stream->priv->conn != NULL, FALSE);
180
181   return g_tls_connection_gnutls_check (tls_stream->priv->conn, G_IO_IN); 
182 }
183
184 static GSource *
185 g_tls_input_stream_gnutls_pollable_create_source (GPollableInputStream *pollable,
186                                                   GCancellable         *cancellable)
187 {
188   GTlsInputStreamGnutls *tls_stream = G_TLS_INPUT_STREAM_GNUTLS (pollable);
189
190   g_return_val_if_fail (tls_stream->priv->conn != NULL, NULL);
191
192   return g_tls_connection_gnutls_create_source (tls_stream->priv->conn,
193                                                 G_IO_IN,
194                                                 cancellable);
195 }
196
197 static gssize
198 g_tls_input_stream_gnutls_pollable_read_nonblocking (GPollableInputStream  *pollable,
199                                                      void                  *buffer,
200                                                      gsize                  size,
201                                                      GError               **error)
202 {
203   GTlsInputStreamGnutls *tls_stream = G_TLS_INPUT_STREAM_GNUTLS (pollable);
204
205   return g_tls_connection_gnutls_read (tls_stream->priv->conn,
206                                        buffer, size, FALSE,
207                                        NULL, error);
208 }
209
210 static void
211 g_tls_input_stream_gnutls_class_init (GTlsInputStreamGnutlsClass *klass)
212 {
213   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
214   GInputStreamClass *input_stream_class = G_INPUT_STREAM_CLASS (klass);
215
216   g_type_class_add_private (klass, sizeof (GTlsInputStreamGnutlsPrivate));
217
218   gobject_class->dispose = g_tls_input_stream_gnutls_dispose;
219
220   input_stream_class->read_fn = g_tls_input_stream_gnutls_read;
221   input_stream_class->read_async = g_tls_input_stream_gnutls_read_async;
222   input_stream_class->read_finish = g_tls_input_stream_gnutls_read_finish;
223 }
224
225 static void
226 g_tls_input_stream_gnutls_pollable_iface_init (GPollableInputStreamInterface *iface)
227 {
228   iface->is_readable = g_tls_input_stream_gnutls_pollable_is_readable;
229   iface->create_source = g_tls_input_stream_gnutls_pollable_create_source;
230   iface->read_nonblocking = g_tls_input_stream_gnutls_pollable_read_nonblocking;
231 }
232
233 static void
234 g_tls_input_stream_gnutls_init (GTlsInputStreamGnutls *stream)
235 {
236   stream->priv = G_TYPE_INSTANCE_GET_PRIVATE (stream, G_TYPE_TLS_INPUT_STREAM_GNUTLS, GTlsInputStreamGnutlsPrivate);
237 }
238
239 GInputStream *
240 g_tls_input_stream_gnutls_new (GTlsConnectionGnutls *conn)
241 {
242   GTlsInputStreamGnutls *tls_stream;
243
244   tls_stream = g_object_new (G_TYPE_TLS_INPUT_STREAM_GNUTLS, NULL);
245   tls_stream->priv->conn = conn;
246   g_object_add_weak_pointer (G_OBJECT (conn),
247                              (gpointer *)&tls_stream->priv->conn);
248
249   return G_INPUT_STREAM (tls_stream);
250 }