dd22be56e852e55cdc8979edcbae1355876343d0
[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
97   if (tls_stream->priv->cancellable)
98     g_object_unref (tls_stream->priv->cancellable);
99   g_simple_async_result_complete (simple);
100   g_object_unref (simple);
101
102   return FALSE;
103 }
104
105 static void
106 g_tls_input_stream_gnutls_read_async (GInputStream        *stream,
107                                       void                *buffer,
108                                       gsize                count,
109                                       gint                 io_priority,
110                                       GCancellable        *cancellable,
111                                       GAsyncReadyCallback  callback,
112                                       gpointer             user_data)
113 {
114   GTlsInputStreamGnutls *tls_stream = G_TLS_INPUT_STREAM_GNUTLS (stream);
115   GSimpleAsyncResult *simple;
116   gssize nread;
117   GError *error = NULL;
118   GSource *source;
119
120   simple = g_simple_async_result_new (G_OBJECT (stream), callback, user_data,
121                                       g_tls_input_stream_gnutls_read_async);
122   nread = g_tls_connection_gnutls_read (tls_stream->priv->conn,
123                                         buffer, count, FALSE,
124                                         cancellable, &error);
125
126   if (nread >= 0 ||
127       !g_error_matches (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK))
128     {
129       if (error)
130         {
131           g_simple_async_result_set_from_error (simple, error);
132           g_error_free (error);
133         }
134       else
135         g_simple_async_result_set_op_res_gssize (simple, nread);
136       g_simple_async_result_complete_in_idle (simple);
137       g_object_unref (simple);
138       return;
139     }
140
141   tls_stream->priv->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
142   tls_stream->priv->buffer = buffer;
143   tls_stream->priv->count = count;
144
145   source = g_tls_connection_gnutls_create_source (tls_stream->priv->conn,
146                                                   G_IO_IN,
147                                                   tls_stream->priv->cancellable);
148   g_source_set_callback (source,
149                          (GSourceFunc) g_tls_input_stream_gnutls_read_ready,
150                          simple, NULL);
151   g_source_attach (source, g_main_context_get_thread_default ());
152   g_source_unref (source);
153 }
154
155 static gssize
156 g_tls_input_stream_gnutls_read_finish (GInputStream  *stream,
157                                        GAsyncResult  *result,
158                                        GError       **error)
159 {
160   g_return_val_if_fail (G_IS_TLS_INPUT_STREAM_GNUTLS (stream), -1);
161   g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (stream), g_tls_input_stream_gnutls_read_async), -1);
162
163   return g_simple_async_result_get_op_res_gssize (G_SIMPLE_ASYNC_RESULT (result));
164 }
165
166 static gboolean
167 g_tls_input_stream_gnutls_pollable_is_readable (GPollableInputStream *pollable)
168 {
169   GTlsInputStreamGnutls *tls_stream = G_TLS_INPUT_STREAM_GNUTLS (pollable);
170
171   return g_tls_connection_gnutls_check (tls_stream->priv->conn, G_IO_IN); 
172 }
173
174 static GSource *
175 g_tls_input_stream_gnutls_pollable_create_source (GPollableInputStream *pollable,
176                                                   GCancellable         *cancellable)
177 {
178   GTlsInputStreamGnutls *tls_stream = G_TLS_INPUT_STREAM_GNUTLS (pollable);
179
180   return g_tls_connection_gnutls_create_source (tls_stream->priv->conn,
181                                                 G_IO_IN,
182                                                 cancellable);
183 }
184
185 static gssize
186 g_tls_input_stream_gnutls_pollable_read_nonblocking (GPollableInputStream  *pollable,
187                                                      void                  *buffer,
188                                                      gsize                  size,
189                                                      GError               **error)
190 {
191   GTlsInputStreamGnutls *tls_stream = G_TLS_INPUT_STREAM_GNUTLS (pollable);
192
193   return g_tls_connection_gnutls_read (tls_stream->priv->conn,
194                                        buffer, size, FALSE,
195                                        NULL, error);
196 }
197
198 static void
199 g_tls_input_stream_gnutls_class_init (GTlsInputStreamGnutlsClass *klass)
200 {
201   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
202   GInputStreamClass *input_stream_class = G_INPUT_STREAM_CLASS (klass);
203
204   g_type_class_add_private (klass, sizeof (GTlsInputStreamGnutlsPrivate));
205
206   gobject_class->finalize = g_tls_input_stream_gnutls_finalize;
207
208   input_stream_class->read_fn = g_tls_input_stream_gnutls_read;
209   input_stream_class->read_async = g_tls_input_stream_gnutls_read_async;
210   input_stream_class->read_finish = g_tls_input_stream_gnutls_read_finish;
211 }
212
213 static void
214 g_tls_input_stream_gnutls_pollable_iface_init (GPollableInputStreamInterface *iface)
215 {
216   iface->is_readable = g_tls_input_stream_gnutls_pollable_is_readable;
217   iface->create_source = g_tls_input_stream_gnutls_pollable_create_source;
218   iface->read_nonblocking = g_tls_input_stream_gnutls_pollable_read_nonblocking;
219 }
220
221 static void
222 g_tls_input_stream_gnutls_init (GTlsInputStreamGnutls *stream)
223 {
224   stream->priv = G_TYPE_INSTANCE_GET_PRIVATE (stream, G_TYPE_TLS_INPUT_STREAM_GNUTLS, GTlsInputStreamGnutlsPrivate);
225 }
226
227 GInputStream *
228 g_tls_input_stream_gnutls_new (GTlsConnectionGnutls *conn)
229 {
230   GTlsInputStreamGnutls *tls_stream;
231
232   tls_stream = g_object_new (G_TYPE_TLS_INPUT_STREAM_GNUTLS, NULL);
233   tls_stream->priv->conn = g_object_ref (conn);
234   return G_INPUT_STREAM (tls_stream);
235 }