Revert "Unref GCancellables if they were reffed by the object."
[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   g_simple_async_result_complete (simple);
97   g_object_unref (simple);
98
99   return FALSE;
100 }
101
102 static void
103 g_tls_output_stream_gnutls_write_async (GOutputStream        *stream,
104                                         const void           *buffer,
105                                         gsize                 count,
106                                         gint                  io_priority,
107                                         GCancellable         *cancellable,
108                                         GAsyncReadyCallback   callback,
109                                         gpointer              user_data)
110 {
111   GTlsOutputStreamGnutls *tls_stream = G_TLS_OUTPUT_STREAM_GNUTLS (stream);
112   GSimpleAsyncResult *simple;
113   gssize nwrote;
114   GError *error = NULL;
115   GSource *source;
116
117   simple = g_simple_async_result_new (G_OBJECT (stream), callback, user_data,
118                                       g_tls_output_stream_gnutls_write_async);
119   nwrote = g_tls_connection_gnutls_write (tls_stream->priv->conn,
120                                           buffer, count, FALSE,
121                                           cancellable, &error);
122
123   if (nwrote >= 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, nwrote);
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_OUT,
144                                                   tls_stream->priv->cancellable);
145   g_source_set_callback (source,
146                          (GSourceFunc) g_tls_output_stream_gnutls_write_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_output_stream_gnutls_write_finish (GOutputStream  *stream,
154                                          GAsyncResult   *result,
155                                          GError        **error)
156 {
157   g_return_val_if_fail (G_IS_TLS_OUTPUT_STREAM_GNUTLS (stream), -1);
158   g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (stream), g_tls_output_stream_gnutls_write_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_output_stream_gnutls_pollable_is_writable (GPollableOutputStream *pollable)
165 {
166   GTlsOutputStreamGnutls *tls_stream = G_TLS_OUTPUT_STREAM_GNUTLS (pollable);
167
168   return g_tls_connection_gnutls_check (tls_stream->priv->conn, G_IO_OUT); 
169 }
170
171 static GSource *
172 g_tls_output_stream_gnutls_pollable_create_source (GPollableOutputStream *pollable,
173                                                    GCancellable         *cancellable)
174 {
175   GTlsOutputStreamGnutls *tls_stream = G_TLS_OUTPUT_STREAM_GNUTLS (pollable);
176
177   return g_tls_connection_gnutls_create_source (tls_stream->priv->conn,
178                                                 G_IO_OUT,
179                                                 cancellable);
180 }
181
182 static gssize
183 g_tls_output_stream_gnutls_pollable_write_nonblocking (GPollableOutputStream  *pollable,
184                                                        const void             *buffer,
185                                                        gsize                   size,
186                                                        GError                **error)
187 {
188   GTlsOutputStreamGnutls *tls_stream = G_TLS_OUTPUT_STREAM_GNUTLS (pollable);
189
190   return g_tls_connection_gnutls_write (tls_stream->priv->conn,
191                                         buffer, size, FALSE,
192                                         NULL, error);
193 }
194
195 static void
196 g_tls_output_stream_gnutls_class_init (GTlsOutputStreamGnutlsClass *klass)
197 {
198   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
199   GOutputStreamClass *output_stream_class = G_OUTPUT_STREAM_CLASS (klass);
200
201   g_type_class_add_private (klass, sizeof (GTlsOutputStreamGnutlsPrivate));
202
203   gobject_class->finalize = g_tls_output_stream_gnutls_finalize;
204
205   output_stream_class->write_fn = g_tls_output_stream_gnutls_write;
206   output_stream_class->write_async = g_tls_output_stream_gnutls_write_async;
207   output_stream_class->write_finish = g_tls_output_stream_gnutls_write_finish;
208 }
209
210 static void
211 g_tls_output_stream_gnutls_pollable_iface_init (GPollableOutputStreamInterface *iface)
212 {
213   iface->is_writable = g_tls_output_stream_gnutls_pollable_is_writable;
214   iface->create_source = g_tls_output_stream_gnutls_pollable_create_source;
215   iface->write_nonblocking = g_tls_output_stream_gnutls_pollable_write_nonblocking;
216 }
217
218 static void
219 g_tls_output_stream_gnutls_init (GTlsOutputStreamGnutls *stream)
220 {
221   stream->priv = G_TYPE_INSTANCE_GET_PRIVATE (stream, G_TYPE_TLS_OUTPUT_STREAM_GNUTLS, GTlsOutputStreamGnutlsPrivate);
222 }
223
224 GOutputStream *
225 g_tls_output_stream_gnutls_new (GTlsConnectionGnutls *conn)
226 {
227   GTlsOutputStreamGnutls *tls_stream;
228
229   tls_stream = g_object_new (G_TYPE_TLS_OUTPUT_STREAM_GNUTLS, NULL);
230   tls_stream->priv->conn = g_object_ref (conn);
231   return G_OUTPUT_STREAM (tls_stream);
232 }