462d74e6c8c13f5b936bbf8b83ee7812511ea422
[platform/upstream/glib-networking.git] / tls / gnutls / gtlsoutputstream-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 "gtlsoutputstream-gnutls.h"
23
24 static void g_tls_output_stream_gnutls_pollable_iface_init (GPollableOutputStreamInterface *iface);
25
26 G_DEFINE_TYPE_WITH_CODE (GTlsOutputStreamGnutls, g_tls_output_stream_gnutls, G_TYPE_OUTPUT_STREAM,
27                          G_IMPLEMENT_INTERFACE (G_TYPE_POLLABLE_OUTPUT_STREAM, g_tls_output_stream_gnutls_pollable_iface_init)
28                          )
29
30 struct _GTlsOutputStreamGnutlsPrivate
31 {
32   GTlsConnectionGnutls *conn;
33
34   /* pending operation metadata */
35   GCancellable *cancellable;
36   gconstpointer buffer;
37   gsize count;
38 };
39
40 static void
41 g_tls_output_stream_gnutls_finalize (GObject *object)
42 {
43   GTlsOutputStreamGnutls *stream = G_TLS_OUTPUT_STREAM_GNUTLS (object);
44
45   if (stream->priv->conn)
46     g_object_unref (stream->priv->conn);
47
48   G_OBJECT_CLASS (g_tls_output_stream_gnutls_parent_class)->finalize (object);
49 }
50
51 static gssize
52 g_tls_output_stream_gnutls_write (GOutputStream  *stream,
53                                   const void     *buffer,
54                                   gsize           count,
55                                   GCancellable   *cancellable,
56                                   GError        **error)
57 {
58   GTlsOutputStreamGnutls *tls_stream = G_TLS_OUTPUT_STREAM_GNUTLS (stream);
59
60   return g_tls_connection_gnutls_write (tls_stream->priv->conn,
61                                         buffer, count, TRUE,
62                                         cancellable, error);
63 }
64
65 static gboolean
66 g_tls_output_stream_gnutls_write_ready (GIOStreamAdapter *adapter,
67                                         gpointer          user_data)
68 {
69   GTlsOutputStreamGnutls *tls_stream;
70   GSimpleAsyncResult *simple = user_data;
71   gssize nwrote;
72   GError *error = NULL;
73
74   tls_stream = G_TLS_OUTPUT_STREAM_GNUTLS (g_async_result_get_source_object (G_ASYNC_RESULT (simple)));
75   g_object_unref (tls_stream);
76
77   nwrote = g_tls_connection_gnutls_write (tls_stream->priv->conn,
78                                           tls_stream->priv->buffer,
79                                           tls_stream->priv->count, FALSE,
80                                           tls_stream->priv->cancellable,
81                                           &error);
82   if (nwrote == -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, nwrote);
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_output_stream_gnutls_write_async (GOutputStream        *stream,
107                                         const void           *buffer,
108                                         gsize                 count,
109                                         gint                  io_priority,
110                                         GCancellable         *cancellable,
111                                         GAsyncReadyCallback   callback,
112                                         gpointer              user_data)
113 {
114   GTlsOutputStreamGnutls *tls_stream = G_TLS_OUTPUT_STREAM_GNUTLS (stream);
115   GSimpleAsyncResult *simple;
116   gssize nwrote;
117   GError *error = NULL;
118   GSource *source;
119
120   simple = g_simple_async_result_new (G_OBJECT (stream), callback, user_data,
121                                       g_tls_output_stream_gnutls_write_async);
122   nwrote = g_tls_connection_gnutls_write (tls_stream->priv->conn,
123                                           buffer, count, FALSE,
124                                           cancellable, &error);
125
126   if (nwrote >= 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, nwrote);
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_OUT,
147                                                   tls_stream->priv->cancellable);
148   g_source_set_callback (source,
149                          (GSourceFunc) g_tls_output_stream_gnutls_write_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_output_stream_gnutls_write_finish (GOutputStream  *stream,
157                                          GAsyncResult   *result,
158                                          GError        **error)
159 {
160   g_return_val_if_fail (G_IS_TLS_OUTPUT_STREAM_GNUTLS (stream), -1);
161   g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (stream), g_tls_output_stream_gnutls_write_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_output_stream_gnutls_pollable_is_writable (GPollableOutputStream *pollable)
168 {
169   GTlsOutputStreamGnutls *tls_stream = G_TLS_OUTPUT_STREAM_GNUTLS (pollable);
170
171   return g_tls_connection_gnutls_check (tls_stream->priv->conn, G_IO_OUT); 
172 }
173
174 static GSource *
175 g_tls_output_stream_gnutls_pollable_create_source (GPollableOutputStream *pollable,
176                                                    GCancellable         *cancellable)
177 {
178   GTlsOutputStreamGnutls *tls_stream = G_TLS_OUTPUT_STREAM_GNUTLS (pollable);
179
180   return g_tls_connection_gnutls_create_source (tls_stream->priv->conn,
181                                                 G_IO_OUT,
182                                                 cancellable);
183 }
184
185 static gssize
186 g_tls_output_stream_gnutls_pollable_write_nonblocking (GPollableOutputStream  *pollable,
187                                                        const void             *buffer,
188                                                        gsize                   size,
189                                                        GError                **error)
190 {
191   GTlsOutputStreamGnutls *tls_stream = G_TLS_OUTPUT_STREAM_GNUTLS (pollable);
192
193   return g_tls_connection_gnutls_write (tls_stream->priv->conn,
194                                         buffer, size, FALSE,
195                                         NULL, error);
196 }
197
198 static void
199 g_tls_output_stream_gnutls_class_init (GTlsOutputStreamGnutlsClass *klass)
200 {
201   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
202   GOutputStreamClass *output_stream_class = G_OUTPUT_STREAM_CLASS (klass);
203
204   g_type_class_add_private (klass, sizeof (GTlsOutputStreamGnutlsPrivate));
205
206   gobject_class->finalize = g_tls_output_stream_gnutls_finalize;
207
208   output_stream_class->write_fn = g_tls_output_stream_gnutls_write;
209   output_stream_class->write_async = g_tls_output_stream_gnutls_write_async;
210   output_stream_class->write_finish = g_tls_output_stream_gnutls_write_finish;
211 }
212
213 static void
214 g_tls_output_stream_gnutls_pollable_iface_init (GPollableOutputStreamInterface *iface)
215 {
216   iface->is_writable = g_tls_output_stream_gnutls_pollable_is_writable;
217   iface->create_source = g_tls_output_stream_gnutls_pollable_create_source;
218   iface->write_nonblocking = g_tls_output_stream_gnutls_pollable_write_nonblocking;
219 }
220
221 static void
222 g_tls_output_stream_gnutls_init (GTlsOutputStreamGnutls *stream)
223 {
224   stream->priv = G_TYPE_INSTANCE_GET_PRIVATE (stream, G_TYPE_TLS_OUTPUT_STREAM_GNUTLS, GTlsOutputStreamGnutlsPrivate);
225 }
226
227 GOutputStream *
228 g_tls_output_stream_gnutls_new (GTlsConnectionGnutls *conn)
229 {
230   GTlsOutputStreamGnutls *tls_stream;
231
232   tls_stream = g_object_new (G_TYPE_TLS_OUTPUT_STREAM_GNUTLS, NULL);
233   tls_stream->priv->conn = g_object_ref (conn);
234   return G_OUTPUT_STREAM (tls_stream);
235 }