c27aee7749fcfcf02328a5c8b43c495c51827908
[platform/upstream/glib-networking.git] / tls / gnutls / gtlsconnection-gnutls.c
1 /* GIO - GLib Input, Output and Streaming Library
2  *
3  * Copyright 2009 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, see
17  * <http://www.gnu.org/licenses/>.
18  */
19
20 #include "config.h"
21 #include "glib.h"
22
23 #include <errno.h>
24 #include <gnutls/gnutls.h>
25 #include <gnutls/x509.h>
26
27 #include "gtlsconnection-gnutls.h"
28 #include "gtlsbackend-gnutls.h"
29 #include "gtlscertificate-gnutls.h"
30 #include "gtlsinputstream-gnutls.h"
31 #include "gtlsoutputstream-gnutls.h"
32 #include "gtlsserverconnection-gnutls.h"
33 #include <glib/gi18n-lib.h>
34
35 static void g_tls_connection_gnutls_get_property (GObject    *object,
36                                                   guint       prop_id,
37                                                   GValue     *value,
38                                                   GParamSpec *pspec);
39 static void g_tls_connection_gnutls_set_property (GObject      *object,
40                                                   guint         prop_id,
41                                                   const GValue *value,
42                                                   GParamSpec   *pspec);
43 static void g_tls_connection_gnutls_finalize     (GObject      *object);
44
45 static gboolean     g_tls_connection_gnutls_handshake        (GTlsConnection       *connection,
46                                                               GCancellable         *cancellable,
47                                                               GError              **error);
48 static void         g_tls_connection_gnutls_handshake_async  (GTlsConnection       *conn,
49                                                               int                   io_priority,
50                                                               GCancellable         *cancellable,
51                                                               GAsyncReadyCallback   callback,
52                                                               gpointer              user_data);
53 static gboolean     g_tls_connection_gnutls_handshake_finish (GTlsConnection       *conn,
54                                                               GAsyncResult         *result,
55                                                               GError              **error);
56
57 static GInputStream  *g_tls_connection_gnutls_get_input_stream  (GIOStream *stream);
58 static GOutputStream *g_tls_connection_gnutls_get_output_stream (GIOStream *stream);
59
60 static gboolean     g_tls_connection_gnutls_close        (GIOStream           *stream,
61                                                           GCancellable        *cancellable,
62                                                           GError             **error);
63 static void         g_tls_connection_gnutls_close_async  (GIOStream           *stream,
64                                                           int                  io_priority,
65                                                           GCancellable        *cancellable,
66                                                           GAsyncReadyCallback  callback,
67                                                           gpointer             user_data);
68 static gboolean     g_tls_connection_gnutls_close_finish (GIOStream           *stream,
69                                                           GAsyncResult        *result,
70                                                           GError             **error);
71
72 static ssize_t g_tls_connection_gnutls_push_func (gnutls_transport_ptr_t  transport_data,
73                                                   const void             *buf,
74                                                   size_t                  buflen);
75 static ssize_t g_tls_connection_gnutls_pull_func (gnutls_transport_ptr_t  transport_data,
76                                                   void                   *buf,
77                                                   size_t                  buflen);
78
79 static void     g_tls_connection_gnutls_initable_iface_init (GInitableIface  *iface);
80 static gboolean g_tls_connection_gnutls_initable_init       (GInitable       *initable,
81                                                              GCancellable    *cancellable,
82                                                              GError         **error);
83
84 static void g_tls_connection_gnutls_init_priorities (void);
85
86 G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GTlsConnectionGnutls, g_tls_connection_gnutls, G_TYPE_TLS_CONNECTION,
87                                   G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,
88                                                          g_tls_connection_gnutls_initable_iface_init);
89                                   g_tls_connection_gnutls_init_priorities ();
90                                   );
91
92
93 enum
94 {
95   PROP_0,
96   PROP_BASE_IO_STREAM,
97   PROP_REQUIRE_CLOSE_NOTIFY,
98   PROP_REHANDSHAKE_MODE,
99   PROP_USE_SYSTEM_CERTDB,
100   PROP_DATABASE,
101   PROP_CERTIFICATE,
102   PROP_INTERACTION,
103   PROP_PEER_CERTIFICATE,
104   PROP_PEER_CERTIFICATE_ERRORS
105 };
106
107 struct _GTlsConnectionGnutlsPrivate
108 {
109   GIOStream *base_io_stream;
110   GPollableInputStream *base_istream;
111   GPollableOutputStream *base_ostream;
112
113   gnutls_certificate_credentials creds;
114   gnutls_session session;
115
116   GTlsCertificate *certificate, *peer_certificate;
117   GTlsCertificateFlags peer_certificate_errors;
118   gboolean require_close_notify;
119   GTlsRehandshakeMode rehandshake_mode;
120   gboolean is_system_certdb;
121   GTlsDatabase *database;
122   gboolean database_is_unset;
123   gboolean need_handshake, handshaking, ever_handshaked;
124   gboolean closing;
125
126   GInputStream *tls_istream;
127   GOutputStream *tls_ostream;
128
129   GTlsInteraction *interaction;
130
131   GError *error;
132   GCancellable *cancellable;
133   gboolean blocking;
134 #ifndef GNUTLS_E_PREMATURE_TERMINATION
135   gboolean eof;
136 #endif
137   GIOCondition internal_direction;
138 };
139
140 static void
141 g_tls_connection_gnutls_class_init (GTlsConnectionGnutlsClass *klass)
142 {
143   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
144   GTlsConnectionClass *connection_class = G_TLS_CONNECTION_CLASS (klass);
145   GIOStreamClass *iostream_class = G_IO_STREAM_CLASS (klass);
146
147   g_type_class_add_private (klass, sizeof (GTlsConnectionGnutlsPrivate));
148
149   gobject_class->get_property = g_tls_connection_gnutls_get_property;
150   gobject_class->set_property = g_tls_connection_gnutls_set_property;
151   gobject_class->finalize     = g_tls_connection_gnutls_finalize;
152
153   connection_class->handshake        = g_tls_connection_gnutls_handshake;
154   connection_class->handshake_async  = g_tls_connection_gnutls_handshake_async;
155   connection_class->handshake_finish = g_tls_connection_gnutls_handshake_finish;
156
157   iostream_class->get_input_stream  = g_tls_connection_gnutls_get_input_stream;
158   iostream_class->get_output_stream = g_tls_connection_gnutls_get_output_stream;
159   iostream_class->close_fn          = g_tls_connection_gnutls_close;
160   iostream_class->close_async       = g_tls_connection_gnutls_close_async;
161   iostream_class->close_finish      = g_tls_connection_gnutls_close_finish;
162
163   g_object_class_override_property (gobject_class, PROP_BASE_IO_STREAM, "base-io-stream");
164   g_object_class_override_property (gobject_class, PROP_REQUIRE_CLOSE_NOTIFY, "require-close-notify");
165   g_object_class_override_property (gobject_class, PROP_REHANDSHAKE_MODE, "rehandshake-mode");
166   g_object_class_override_property (gobject_class, PROP_USE_SYSTEM_CERTDB, "use-system-certdb");
167   g_object_class_override_property (gobject_class, PROP_DATABASE, "database");
168   g_object_class_override_property (gobject_class, PROP_CERTIFICATE, "certificate");
169   g_object_class_override_property (gobject_class, PROP_INTERACTION, "interaction");
170   g_object_class_override_property (gobject_class, PROP_PEER_CERTIFICATE, "peer-certificate");
171   g_object_class_override_property (gobject_class, PROP_PEER_CERTIFICATE_ERRORS, "peer-certificate-errors");
172 }
173
174 static void
175 g_tls_connection_gnutls_initable_iface_init (GInitableIface *iface)
176 {
177   iface->init = g_tls_connection_gnutls_initable_init;
178 }
179
180 static void
181 g_tls_connection_gnutls_init (GTlsConnectionGnutls *gnutls)
182 {
183   gnutls->priv = G_TYPE_INSTANCE_GET_PRIVATE (gnutls, G_TYPE_TLS_CONNECTION_GNUTLS, GTlsConnectionGnutlsPrivate);
184
185   gnutls_certificate_allocate_credentials (&gnutls->priv->creds);
186   gnutls_certificate_set_verify_flags (gnutls->priv->creds,
187                                        GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT);
188
189   gnutls->priv->need_handshake = TRUE;
190
191   gnutls->priv->database_is_unset = TRUE;
192   gnutls->priv->is_system_certdb = TRUE;
193 }
194
195 static gnutls_priority_t priorities[2][2];
196
197 static void
198 g_tls_connection_gnutls_init_priorities (void)
199 {
200   /* First field is "ssl3 only", second is "allow unsafe rehandshaking" */
201
202   gnutls_priority_init (&priorities[FALSE][FALSE],
203                         "NORMAL:%COMPAT",
204                         NULL);
205   gnutls_priority_init (&priorities[TRUE][FALSE],
206                         "NORMAL:%COMPAT:!VERS-TLS1.2:!VERS-TLS1.1:!VERS-TLS1.0",
207                         NULL);
208   gnutls_priority_init (&priorities[FALSE][TRUE],
209                         "NORMAL:%COMPAT:%UNSAFE_RENEGOTIATION",
210                         NULL);
211   gnutls_priority_init (&priorities[TRUE][TRUE],
212                         "NORMAL:%COMPAT:!VERS-TLS1.2:!VERS-TLS1.1:!VERS-TLS1.0:%UNSAFE_RENEGOTIATION",
213                         NULL);
214 }
215
216 static void
217 g_tls_connection_gnutls_set_handshake_priority (GTlsConnectionGnutls *gnutls)
218 {
219   gboolean use_ssl3, unsafe_rehandshake;
220
221   if (G_IS_TLS_CLIENT_CONNECTION (gnutls))
222     use_ssl3 = g_tls_client_connection_get_use_ssl3 (G_TLS_CLIENT_CONNECTION (gnutls));
223   else
224     use_ssl3 = FALSE;
225   unsafe_rehandshake = (gnutls->priv->rehandshake_mode == G_TLS_REHANDSHAKE_UNSAFELY);
226   gnutls_priority_set (gnutls->priv->session,
227                        priorities[use_ssl3][unsafe_rehandshake]);
228 }
229
230 static gboolean
231 g_tls_connection_gnutls_initable_init (GInitable     *initable,
232                                        GCancellable  *cancellable,
233                                        GError       **error)
234 {
235   GTlsConnectionGnutls *gnutls = G_TLS_CONNECTION_GNUTLS (initable);
236   int status;
237
238   g_return_val_if_fail (gnutls->priv->base_istream != NULL &&
239                         gnutls->priv->base_ostream != NULL, FALSE);
240
241   /* Make sure gnutls->priv->session has been initialized (it may have
242    * already been initialized by a construct-time property setter).
243    */
244   g_tls_connection_gnutls_get_session (gnutls);
245
246   status = gnutls_credentials_set (gnutls->priv->session,
247                                    GNUTLS_CRD_CERTIFICATE,
248                                    gnutls->priv->creds);
249   if (status != 0)
250     {
251       g_set_error (error, G_TLS_ERROR, G_TLS_ERROR_MISC,
252                    _("Could not create TLS connection: %s"),
253                    gnutls_strerror (status));
254       return FALSE;
255     }
256
257   /* Some servers (especially on embedded devices) use tiny keys that
258    * gnutls will reject by default. We want it to accept them.
259    */
260   gnutls_dh_set_prime_bits (gnutls->priv->session, 256);
261
262   gnutls_transport_set_push_function (gnutls->priv->session,
263                                       g_tls_connection_gnutls_push_func);
264   gnutls_transport_set_pull_function (gnutls->priv->session,
265                                       g_tls_connection_gnutls_pull_func);
266   gnutls_transport_set_ptr (gnutls->priv->session, gnutls);
267
268   gnutls->priv->tls_istream = g_tls_input_stream_gnutls_new (gnutls);
269   gnutls->priv->tls_ostream = g_tls_output_stream_gnutls_new (gnutls);
270
271   return TRUE;
272 }
273
274 static void
275 g_tls_connection_gnutls_finalize (GObject *object)
276 {
277   GTlsConnectionGnutls *connection = G_TLS_CONNECTION_GNUTLS (object);
278
279   if (connection->priv->base_io_stream)
280     g_object_unref (connection->priv->base_io_stream);
281
282   if (connection->priv->session)
283     gnutls_deinit (connection->priv->session);
284
285   if (connection->priv->tls_istream)
286     g_object_unref (connection->priv->tls_istream);
287   if (connection->priv->tls_ostream) 
288     g_object_unref (connection->priv->tls_ostream);
289
290   if (connection->priv->creds)
291     gnutls_certificate_free_credentials (connection->priv->creds);
292
293   if (connection->priv->database)
294     g_object_unref (connection->priv->database);
295   if (connection->priv->certificate)
296     g_object_unref (connection->priv->certificate);
297   if (connection->priv->peer_certificate)
298     g_object_unref (connection->priv->peer_certificate);
299
300   g_clear_object (&connection->priv->interaction);
301
302   if (connection->priv->error)
303     g_error_free (connection->priv->error);
304
305   G_OBJECT_CLASS (g_tls_connection_gnutls_parent_class)->finalize (object);
306 }
307
308 static void
309 g_tls_connection_gnutls_get_property (GObject    *object,
310                                       guint       prop_id,
311                                       GValue     *value,
312                                       GParamSpec *pspec)
313 {
314   GTlsConnectionGnutls *gnutls = G_TLS_CONNECTION_GNUTLS (object);
315   GTlsBackend *backend;
316
317   switch (prop_id)
318     {
319     case PROP_BASE_IO_STREAM:
320       g_value_set_object (value, gnutls->priv->base_io_stream);
321       break;
322
323     case PROP_REQUIRE_CLOSE_NOTIFY:
324       g_value_set_boolean (value, gnutls->priv->require_close_notify);
325       break;
326
327     case PROP_REHANDSHAKE_MODE:
328       g_value_set_enum (value, gnutls->priv->rehandshake_mode);
329       break;
330
331     case PROP_USE_SYSTEM_CERTDB:
332       g_value_set_boolean (value, gnutls->priv->is_system_certdb);
333       break;
334
335     case PROP_DATABASE:
336       if (gnutls->priv->database_is_unset)
337         {
338           backend = g_tls_backend_get_default ();
339           gnutls->priv->database =  g_tls_backend_get_default_database (backend);
340           gnutls->priv->database_is_unset = FALSE;
341         }
342       g_value_set_object (value, gnutls->priv->database);
343       break;
344
345     case PROP_CERTIFICATE:
346       g_value_set_object (value, gnutls->priv->certificate);
347       break;
348
349     case PROP_INTERACTION:
350       g_value_set_object (value, gnutls->priv->interaction);
351       break;
352
353     case PROP_PEER_CERTIFICATE:
354       g_value_set_object (value, gnutls->priv->peer_certificate);
355       break;
356
357     case PROP_PEER_CERTIFICATE_ERRORS:
358       g_value_set_flags (value, gnutls->priv->peer_certificate_errors);
359       break;
360
361     default:
362       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
363     }
364 }
365
366 static void
367 g_tls_connection_gnutls_set_property (GObject      *object,
368                                       guint         prop_id,
369                                       const GValue *value,
370                                       GParamSpec   *pspec)
371 {
372   GTlsConnectionGnutls *gnutls = G_TLS_CONNECTION_GNUTLS (object);
373   GInputStream *istream;
374   GOutputStream *ostream;
375   gboolean system_certdb;
376   GTlsBackend *backend;
377
378   switch (prop_id)
379     {
380     case PROP_BASE_IO_STREAM:
381       if (gnutls->priv->base_io_stream)
382         {
383           g_object_unref (gnutls->priv->base_io_stream);
384           gnutls->priv->base_istream = NULL;
385           gnutls->priv->base_ostream = NULL;
386         }
387       gnutls->priv->base_io_stream = g_value_dup_object (value);
388       if (!gnutls->priv->base_io_stream)
389         return;
390
391       istream = g_io_stream_get_input_stream (gnutls->priv->base_io_stream);
392       ostream = g_io_stream_get_output_stream (gnutls->priv->base_io_stream);
393
394       if (G_IS_POLLABLE_INPUT_STREAM (istream) &&
395           g_pollable_input_stream_can_poll (G_POLLABLE_INPUT_STREAM (istream)))
396         gnutls->priv->base_istream = G_POLLABLE_INPUT_STREAM (istream);
397       if (G_IS_POLLABLE_OUTPUT_STREAM (ostream) &&
398           g_pollable_output_stream_can_poll (G_POLLABLE_OUTPUT_STREAM (ostream)))
399         gnutls->priv->base_ostream = G_POLLABLE_OUTPUT_STREAM (ostream);
400       break;
401
402     case PROP_REQUIRE_CLOSE_NOTIFY:
403       gnutls->priv->require_close_notify = g_value_get_boolean (value);
404       break;
405
406     case PROP_REHANDSHAKE_MODE:
407       gnutls->priv->rehandshake_mode = g_value_get_enum (value);
408       break;
409
410     case PROP_USE_SYSTEM_CERTDB:
411       system_certdb = g_value_get_boolean (value);
412       if (system_certdb != gnutls->priv->is_system_certdb)
413         {
414           g_clear_object (&gnutls->priv->database);
415           if (system_certdb)
416             {
417               backend = g_tls_backend_get_default ();
418               gnutls->priv->database = g_tls_backend_get_default_database (backend);
419             }
420           gnutls->priv->is_system_certdb = system_certdb;
421         }
422       break;
423
424     case PROP_DATABASE:
425       g_clear_object (&gnutls->priv->database);
426       gnutls->priv->database = g_value_dup_object (value);
427       gnutls->priv->is_system_certdb = FALSE;
428       gnutls->priv->database_is_unset = FALSE;
429       break;
430
431     case PROP_CERTIFICATE:
432       if (gnutls->priv->certificate)
433         g_object_unref (gnutls->priv->certificate);
434       gnutls->priv->certificate = g_value_dup_object (value);
435       break;
436
437     case PROP_INTERACTION:
438       g_clear_object (&gnutls->priv->interaction);
439       gnutls->priv->interaction = g_value_dup_object (value);
440       break;
441
442     default:
443       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
444     }
445 }
446
447 gnutls_certificate_credentials
448 g_tls_connection_gnutls_get_credentials (GTlsConnectionGnutls *gnutls)
449 {
450   return gnutls->priv->creds;
451 }
452
453 gnutls_session
454 g_tls_connection_gnutls_get_session (GTlsConnectionGnutls *gnutls)
455 {
456   /* Ideally we would initialize gnutls->priv->session from
457    * g_tls_connection_gnutls_init(), but we can't tell if it's a
458    * client or server connection at that point... And
459    * g_tls_connection_gnutls_initiable_init() is too late, because
460    * construct-time property setters may need to modify it.
461    */
462   if (!gnutls->priv->session)
463     {
464       gboolean client = G_IS_TLS_CLIENT_CONNECTION (gnutls);
465       gnutls_init (&gnutls->priv->session, client ? GNUTLS_CLIENT : GNUTLS_SERVER);
466     }
467
468   return gnutls->priv->session;
469 }
470
471 void
472 g_tls_connection_gnutls_get_certificate (GTlsConnectionGnutls *gnutls,
473                                          gnutls_retr2_st      *st)
474 {
475   GTlsCertificate *cert;
476
477   cert = g_tls_connection_get_certificate (G_TLS_CONNECTION (gnutls));
478
479   st->cert_type = GNUTLS_CRT_X509;
480   if (cert)
481     {
482       GTlsCertificateGnutls *gnutlscert = G_TLS_CERTIFICATE_GNUTLS (cert);
483
484       st->ncerts = 1;
485       st->cert.x509 = gnutls_malloc (sizeof (gnutls_x509_crt_t));
486       st->cert.x509[0] = g_tls_certificate_gnutls_copy_cert (gnutlscert);
487       st->key.x509 = g_tls_certificate_gnutls_copy_key (gnutlscert);
488       st->deinit_all = TRUE;
489     }
490   else
491     st->ncerts = 0;
492 }
493
494 static void
495 begin_gnutls_io (GTlsConnectionGnutls  *gnutls,
496                  gboolean               blocking,
497                  GCancellable          *cancellable)
498 {
499   gnutls->priv->blocking = blocking;
500   gnutls->priv->cancellable = cancellable;
501   gnutls->priv->internal_direction = 0;
502   g_clear_error (&gnutls->priv->error);
503 }
504
505 static int
506 end_gnutls_io (GTlsConnectionGnutls  *gnutls,
507                int                    status,
508                GError               **error)
509 {
510   gnutls->priv->cancellable = NULL;
511
512   if (status >= 0)
513     {
514       g_clear_error (&gnutls->priv->error);
515       return status;
516     }
517
518   if (gnutls->priv->handshaking && !gnutls->priv->ever_handshaked)
519     {
520       if (g_error_matches (gnutls->priv->error, G_IO_ERROR, G_IO_ERROR_FAILED) ||
521           status == GNUTLS_E_UNEXPECTED_PACKET_LENGTH ||
522           status == GNUTLS_E_FATAL_ALERT_RECEIVED ||
523           status == GNUTLS_E_DECRYPTION_FAILED ||
524           status == GNUTLS_E_UNSUPPORTED_VERSION_PACKET)
525         {
526           g_clear_error (&gnutls->priv->error);
527           g_set_error_literal (error, G_TLS_ERROR, G_TLS_ERROR_NOT_TLS,
528                                _("Peer failed to perform TLS handshake"));
529           return GNUTLS_E_PULL_ERROR;
530         }
531     }
532
533   if (gnutls->priv->error)
534     {
535       if (g_error_matches (gnutls->priv->error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK))
536         status = GNUTLS_E_AGAIN;
537       g_propagate_error (error, gnutls->priv->error);
538       gnutls->priv->error = NULL;
539       return status;
540     }
541   else if (status == GNUTLS_E_REHANDSHAKE)
542     {
543       if (gnutls->priv->rehandshake_mode == G_TLS_REHANDSHAKE_NEVER)
544         {
545           g_set_error_literal (error, G_TLS_ERROR, G_TLS_ERROR_MISC,
546                                _("Peer requested illegal TLS rehandshake"));
547           return GNUTLS_E_PULL_ERROR;
548         }
549
550       gnutls->priv->need_handshake = TRUE;
551       return status;
552     }
553   else if (
554 #ifdef GNUTLS_E_PREMATURE_TERMINATION
555            status == GNUTLS_E_PREMATURE_TERMINATION
556 #else
557            status == GNUTLS_E_UNEXPECTED_PACKET_LENGTH && gnutls->priv->eof
558 #endif
559            )
560     {
561       if (gnutls->priv->require_close_notify)
562         {
563           g_set_error_literal (error, G_TLS_ERROR, G_TLS_ERROR_EOF,
564                                _("TLS connection closed unexpectedly"));
565           return status;
566         }
567       else
568         return 0;
569     }
570
571   return status;
572 }
573
574 #define BEGIN_GNUTLS_IO(gnutls, blocking, cancellable)  \
575   begin_gnutls_io (gnutls, blocking, cancellable);      \
576   do {
577
578 #define END_GNUTLS_IO(gnutls, ret, errmsg, error)       \
579   } while ((ret == GNUTLS_E_AGAIN ||                    \
580             ret == GNUTLS_E_WARNING_ALERT_RECEIVED) &&  \
581            !gnutls->priv->error);                       \
582   ret = end_gnutls_io (gnutls, ret, error);             \
583   if (ret < 0 && ret != GNUTLS_E_REHANDSHAKE && error && !*error) \
584     {                                                   \
585       g_set_error (error, G_TLS_ERROR, G_TLS_ERROR_MISC,\
586                    errmsg, gnutls_strerror (ret));      \
587     }                                                   \
588   ;
589
590 gboolean
591 g_tls_connection_gnutls_check (GTlsConnectionGnutls  *gnutls,
592                                GIOCondition           condition)
593 {
594   if (!gnutls->priv->internal_direction)
595     return TRUE;
596
597   if (gnutls->priv->handshaking || gnutls->priv->closing)
598     condition = gnutls->priv->internal_direction;
599
600   if (condition & G_IO_IN)
601     return g_pollable_input_stream_is_readable (gnutls->priv->base_istream);
602   else
603     return g_pollable_output_stream_is_writable (gnutls->priv->base_ostream);
604 }
605
606 typedef struct {
607   GSource source;
608
609   GTlsConnectionGnutls *gnutls;
610   GObject              *stream;
611
612   GSource              *child_source;
613   GIOCondition          current_direction;
614 } GTlsConnectionGnutlsSource;
615
616 static gboolean
617 gnutls_source_prepare (GSource *source,
618                        gint    *timeout)
619 {
620   *timeout = -1;
621   return FALSE;
622 }
623
624 static gboolean
625 gnutls_source_check (GSource *source)
626 {
627   return FALSE;
628 }
629
630 static gboolean
631 gnutls_source_sync_child_source (GTlsConnectionGnutlsSource *gnutls_source)
632 {
633   GTlsConnectionGnutls *gnutls = gnutls_source->gnutls;
634   GSource *source = (GSource *)gnutls_source;
635   GIOCondition direction;
636
637   if (gnutls->priv->handshaking || gnutls->priv->closing)
638     direction = gnutls->priv->internal_direction;
639   else if (!gnutls_source->stream)
640     return FALSE;
641   else if (G_IS_TLS_INPUT_STREAM_GNUTLS (gnutls_source->stream))
642     direction = G_IO_IN;
643   else
644     direction = G_IO_OUT;
645
646   if (direction == gnutls_source->current_direction)
647     return TRUE;
648
649   if (gnutls_source->child_source)
650     {
651       g_source_remove_child_source (source, gnutls_source->child_source);
652       g_source_unref (gnutls_source->child_source);
653     }
654
655   if (direction & G_IO_IN)
656     gnutls_source->child_source = g_pollable_input_stream_create_source (gnutls->priv->base_istream, NULL);
657   else
658     gnutls_source->child_source = g_pollable_output_stream_create_source (gnutls->priv->base_ostream, NULL);
659
660   g_source_set_dummy_callback (gnutls_source->child_source);
661   g_source_add_child_source (source, gnutls_source->child_source);
662   gnutls_source->current_direction = direction;
663   return TRUE;
664 }
665
666 static gboolean
667 gnutls_source_dispatch (GSource     *source,
668                         GSourceFunc  callback,
669                         gpointer     user_data)
670 {
671   GPollableSourceFunc func = (GPollableSourceFunc)callback;
672   GTlsConnectionGnutlsSource *gnutls_source = (GTlsConnectionGnutlsSource *)source;
673   gboolean ret;
674
675   ret = (*func) (gnutls_source->stream, user_data);
676   if (ret)
677     ret = gnutls_source_sync_child_source (gnutls_source);
678
679   return ret;
680 }
681
682 static void
683 gnutls_source_finalize (GSource *source)
684 {
685   GTlsConnectionGnutlsSource *gnutls_source = (GTlsConnectionGnutlsSource *)source;
686
687   g_object_unref (gnutls_source->gnutls);
688
689   if (gnutls_source->child_source)
690     g_source_unref (gnutls_source->child_source);
691 }
692
693 static gboolean
694 g_tls_connection_gnutls_source_closure_callback (GObject  *stream,
695                                                  gpointer  data)
696 {
697   GClosure *closure = data;
698
699   GValue param = { 0, };
700   GValue result_value = { 0, };
701   gboolean result;
702
703   g_value_init (&result_value, G_TYPE_BOOLEAN);
704
705   g_value_init (&param, G_TYPE_OBJECT);
706   g_value_set_object (&param, stream);
707
708   g_closure_invoke (closure, &result_value, 1, &param, NULL);
709
710   result = g_value_get_boolean (&result_value);
711   g_value_unset (&result_value);
712   g_value_unset (&param);
713
714   return result;
715 }
716
717 static GSourceFuncs gnutls_source_funcs =
718 {
719   gnutls_source_prepare,
720   gnutls_source_check,
721   gnutls_source_dispatch,
722   gnutls_source_finalize,
723   (GSourceFunc)g_tls_connection_gnutls_source_closure_callback,
724   (GSourceDummyMarshal)g_cclosure_marshal_generic
725 };
726
727 GSource *
728 g_tls_connection_gnutls_create_source (GTlsConnectionGnutls  *gnutls,
729                                        GIOCondition           condition,
730                                        GCancellable          *cancellable)
731 {
732   GSource *source, *cancellable_source;
733   GTlsConnectionGnutlsSource *gnutls_source;
734
735   source = g_source_new (&gnutls_source_funcs, sizeof (GTlsConnectionGnutlsSource));
736   g_source_set_name (source, "GTlsConnectionGnutlsSource");
737   gnutls_source = (GTlsConnectionGnutlsSource *)source;
738   gnutls_source->gnutls = g_object_ref (gnutls);
739   if (condition & G_IO_IN)
740     gnutls_source->stream = G_OBJECT (gnutls->priv->tls_istream);
741   else if (condition & G_IO_OUT)
742     gnutls_source->stream = G_OBJECT (gnutls->priv->tls_ostream);
743   gnutls_source_sync_child_source (gnutls_source);
744
745   if (cancellable)
746     {
747       cancellable_source = g_cancellable_source_new (cancellable);
748       g_source_set_dummy_callback (cancellable_source);
749       g_source_add_child_source (source, cancellable_source);
750       g_source_unref (cancellable_source);
751     }
752
753   return source;
754 }
755
756 static void
757 set_gnutls_error (GTlsConnectionGnutls *gnutls, GIOCondition direction)
758 {
759   if (g_error_matches (gnutls->priv->error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
760     gnutls_transport_set_errno (gnutls->priv->session, EINTR);
761   else if (g_error_matches (gnutls->priv->error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK))
762     {
763       gnutls_transport_set_errno (gnutls->priv->session, EAGAIN);
764       gnutls->priv->internal_direction = direction;
765     }
766   else
767     gnutls_transport_set_errno (gnutls->priv->session, EIO);
768 }
769
770 static ssize_t
771 g_tls_connection_gnutls_pull_func (gnutls_transport_ptr_t  transport_data,
772                                    void                   *buf,
773                                    size_t                  buflen)
774 {
775   GTlsConnectionGnutls *gnutls = transport_data;
776   ssize_t ret;
777
778   /* If gnutls->priv->error is non-%NULL when we're called, it means
779    * that an error previously occurred, but gnutls decided not to
780    * propagate it. So it's correct for us to just clear it. (Usually
781    * this means it ignored an EAGAIN after a short read, and now
782    * we'll return EAGAIN again, which it will obey this time.)
783    */
784   g_clear_error (&gnutls->priv->error);
785
786   if (gnutls->priv->blocking)
787     {
788       ret = g_input_stream_read (G_INPUT_STREAM (gnutls->priv->base_istream),
789                                  buf, buflen,
790                                  gnutls->priv->cancellable,
791                                  &gnutls->priv->error);
792     }
793   else
794     {
795       ret = g_pollable_input_stream_read_nonblocking (gnutls->priv->base_istream,
796                                                       buf, buflen,
797                                                       gnutls->priv->cancellable,
798                                                       &gnutls->priv->error);
799     }
800
801   if (ret < 0)
802     set_gnutls_error (gnutls, G_IO_IN);
803 #ifndef GNUTLS_E_PREMATURE_TERMINATION
804   else if (ret == 0)
805     gnutls->priv->eof = TRUE;
806 #endif
807
808   return ret;
809 }
810
811 static ssize_t
812 g_tls_connection_gnutls_push_func (gnutls_transport_ptr_t  transport_data,
813                                    const void             *buf,
814                                    size_t                  buflen)
815 {
816   GTlsConnectionGnutls *gnutls = transport_data;
817   ssize_t ret;
818
819   /* See comment in pull_func. */
820   g_clear_error (&gnutls->priv->error);
821
822   if (gnutls->priv->blocking)
823     {
824       ret = g_output_stream_write (G_OUTPUT_STREAM (gnutls->priv->base_ostream),
825                                    buf, buflen,
826                                    gnutls->priv->cancellable,
827                                    &gnutls->priv->error);
828     }
829   else
830     {
831       ret = g_pollable_output_stream_write_nonblocking (gnutls->priv->base_ostream,
832                                                         buf, buflen,
833                                                         gnutls->priv->cancellable,
834                                                         &gnutls->priv->error);
835     }
836   if (ret < 0)
837     set_gnutls_error (gnutls, G_IO_OUT);
838
839   return ret;
840 }
841
842 static gboolean
843 handshake_internal (GTlsConnectionGnutls  *gnutls,
844                     gboolean               blocking,
845                     GCancellable          *cancellable,
846                     GError               **error)
847 {
848   GTlsCertificate *peer_certificate = NULL;
849   GTlsCertificateFlags peer_certificate_errors = 0;
850   int ret;
851
852   if (G_IS_TLS_SERVER_CONNECTION_GNUTLS (gnutls) &&
853       gnutls->priv->ever_handshaked && !gnutls->priv->handshaking &&
854       !gnutls->priv->need_handshake)
855     {
856       BEGIN_GNUTLS_IO (gnutls, blocking, cancellable);
857       ret = gnutls_rehandshake (gnutls->priv->session);
858       END_GNUTLS_IO (gnutls, ret, _("Error performing TLS handshake: %s"), error);
859
860       if (ret != 0)
861         return FALSE;
862     }
863
864   if (!gnutls->priv->handshaking)
865     {
866       gnutls->priv->handshaking = TRUE;
867
868       if (gnutls->priv->peer_certificate)
869         {
870           g_object_unref (gnutls->priv->peer_certificate);
871           gnutls->priv->peer_certificate = NULL;
872           gnutls->priv->peer_certificate_errors = 0;
873
874           g_object_notify (G_OBJECT (gnutls), "peer-certificate");
875           g_object_notify (G_OBJECT (gnutls), "peer-certificate-errors");
876         }
877
878       g_tls_connection_gnutls_set_handshake_priority (gnutls);
879       G_TLS_CONNECTION_GNUTLS_GET_CLASS (gnutls)->begin_handshake (gnutls);
880     }
881
882   BEGIN_GNUTLS_IO (gnutls, blocking, cancellable);
883   ret = gnutls_handshake (gnutls->priv->session);
884   END_GNUTLS_IO (gnutls, ret, _("Error performing TLS handshake: %s"), error);
885
886   if (ret == GNUTLS_E_AGAIN)
887     return FALSE;
888
889   gnutls->priv->handshaking = FALSE;
890   gnutls->priv->need_handshake = FALSE;
891   gnutls->priv->ever_handshaked = TRUE;
892
893   if (ret == 0 &&
894       gnutls_certificate_type_get (gnutls->priv->session) == GNUTLS_CRT_X509)
895     {
896       GTlsCertificate *chain, *cert;
897       const gnutls_datum_t *certs;
898       unsigned int num_certs;
899       int i;
900
901       certs = gnutls_certificate_get_peers (gnutls->priv->session, &num_certs);
902       chain = NULL;
903       if (certs)
904         {
905           for (i = num_certs - 1; i >= 0; i--)
906             {
907               cert = g_tls_certificate_gnutls_new (&certs[i], chain);
908               if (chain)
909                 g_object_unref (chain);
910               chain = cert;
911             }
912         }
913
914       peer_certificate = chain;
915     }
916
917   if (peer_certificate)
918     {
919       if (!G_TLS_CONNECTION_GNUTLS_GET_CLASS (gnutls)->verify_peer (gnutls, peer_certificate, &peer_certificate_errors))
920         {
921           g_object_unref (peer_certificate);
922           g_set_error_literal (error, G_TLS_ERROR, G_TLS_ERROR_BAD_CERTIFICATE,
923                                _("Unacceptable TLS certificate"));
924           return FALSE;
925         }
926     }
927
928   G_TLS_CONNECTION_GNUTLS_GET_CLASS (gnutls)->finish_handshake (gnutls, ret == 0, error);
929
930   if (ret == 0)
931     {
932       gnutls->priv->peer_certificate = peer_certificate;
933       gnutls->priv->peer_certificate_errors = peer_certificate_errors;
934
935       g_object_notify (G_OBJECT (gnutls), "peer-certificate");
936       g_object_notify (G_OBJECT (gnutls), "peer-certificate-errors");
937
938       return TRUE;
939     }
940   else
941     return FALSE;
942 }
943
944 static gboolean
945 handshake_in_progress_or_failed (GTlsConnectionGnutls  *gnutls,
946                                  gboolean               blocking,
947                                  GCancellable          *cancellable,
948                                  GError               **error)
949 {
950   if (!(gnutls->priv->need_handshake || gnutls->priv->handshaking))
951     return FALSE;
952
953   return !handshake_internal (gnutls, blocking, cancellable, error);
954 }
955
956 static gboolean
957 g_tls_connection_gnutls_handshake (GTlsConnection   *conn,
958                                    GCancellable     *cancellable,
959                                    GError          **error)
960 {
961   GTlsConnectionGnutls *gnutls = G_TLS_CONNECTION_GNUTLS (conn);
962
963   return handshake_internal (gnutls, TRUE, cancellable, error);
964 }
965
966 static gboolean
967 g_tls_connection_gnutls_handshake_ready (GObject  *pollable_stream,
968                                          gpointer  user_data)
969 {
970   GTlsConnectionGnutls *gnutls;
971   GSimpleAsyncResult *simple = user_data;
972   gboolean success;
973   GError *error = NULL;
974
975   gnutls = G_TLS_CONNECTION_GNUTLS (g_async_result_get_source_object (G_ASYNC_RESULT (simple)));
976   g_object_unref (gnutls);
977
978   success = handshake_internal (gnutls, FALSE, NULL, &error);
979   if (!success && g_error_matches (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK))
980     {
981       g_error_free (error);
982       return TRUE;
983     }
984
985   if (error)
986     {
987       g_simple_async_result_set_from_error (simple, error);
988       g_error_free (error);
989     }
990   else
991     g_simple_async_result_set_op_res_gboolean (simple, success);
992   g_simple_async_result_complete (simple);
993   g_object_unref (simple);
994
995   return FALSE;
996 }
997
998 static void
999 g_tls_connection_gnutls_handshake_async (GTlsConnection       *conn,
1000                                          int                   io_priority,
1001                                          GCancellable         *cancellable,
1002                                          GAsyncReadyCallback   callback,
1003                                          gpointer              user_data)
1004 {
1005   GTlsConnectionGnutls *gnutls = G_TLS_CONNECTION_GNUTLS (conn);
1006   GSimpleAsyncResult *simple;
1007   gboolean success;
1008   GError *error = NULL;
1009   GSource *source;
1010
1011   simple = g_simple_async_result_new (G_OBJECT (conn), callback, user_data,
1012                                       g_tls_connection_gnutls_handshake_async);
1013   success = handshake_internal (gnutls, FALSE, cancellable, &error);
1014   if (success)
1015     {
1016       g_simple_async_result_set_op_res_gboolean (simple, TRUE);
1017       g_simple_async_result_complete_in_idle (simple);
1018       g_object_unref (simple);
1019     }
1020   else if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK))
1021     {
1022       g_simple_async_result_set_from_error (simple, error);
1023       g_error_free (error);
1024       g_simple_async_result_complete_in_idle (simple);
1025       g_object_unref (simple);
1026     }
1027   else if (error)
1028     g_error_free (error);
1029
1030   source = g_tls_connection_gnutls_create_source (gnutls, 0, cancellable);
1031   g_source_set_callback (source,
1032                          (GSourceFunc) g_tls_connection_gnutls_handshake_ready,
1033                          simple, NULL);
1034   g_source_set_priority (source, io_priority);
1035   g_source_attach (source, g_main_context_get_thread_default ());
1036   g_source_unref (source);
1037 }
1038
1039 static gboolean
1040 g_tls_connection_gnutls_handshake_finish (GTlsConnection       *conn,
1041                                           GAsyncResult         *result,
1042                                           GError              **error)
1043 {
1044   GSimpleAsyncResult *simple;
1045
1046   g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (conn), g_tls_connection_gnutls_handshake_async), FALSE);
1047
1048   simple = G_SIMPLE_ASYNC_RESULT (result);
1049
1050   if (g_simple_async_result_propagate_error (simple, error))
1051     return FALSE;
1052
1053   return g_simple_async_result_get_op_res_gboolean (simple);
1054 }
1055
1056 gssize
1057 g_tls_connection_gnutls_read (GTlsConnectionGnutls  *gnutls,
1058                               void                  *buffer,
1059                               gsize                  count,
1060                               gboolean               blocking,
1061                               GCancellable          *cancellable,
1062                               GError               **error)
1063 {
1064   gssize ret;
1065
1066  again:
1067   if (handshake_in_progress_or_failed (gnutls, blocking, cancellable, error))
1068     return -1;
1069
1070   BEGIN_GNUTLS_IO (gnutls, blocking, cancellable);
1071   ret = gnutls_record_recv (gnutls->priv->session, buffer, count);
1072   END_GNUTLS_IO (gnutls, ret, _("Error reading data from TLS socket: %s"), error);
1073
1074   if (ret >= 0)
1075     return ret;
1076   else if (ret == GNUTLS_E_REHANDSHAKE)
1077     goto again;
1078   else
1079     return -1;
1080 }
1081
1082 gssize
1083 g_tls_connection_gnutls_write (GTlsConnectionGnutls  *gnutls,
1084                                const void            *buffer,
1085                                gsize                  count,
1086                                gboolean               blocking,
1087                                GCancellable          *cancellable,
1088                                GError               **error)
1089 {
1090   gssize ret;
1091
1092  again:
1093   if (handshake_in_progress_or_failed (gnutls, blocking, cancellable, error))
1094     return -1;
1095
1096   BEGIN_GNUTLS_IO (gnutls, blocking, cancellable);
1097   ret = gnutls_record_send (gnutls->priv->session, buffer, count);
1098   END_GNUTLS_IO (gnutls, ret, _("Error writing data to TLS socket: %s"), error);
1099
1100   if (ret >= 0)
1101     return ret;
1102   else if (ret == GNUTLS_E_REHANDSHAKE)
1103     goto again;
1104   else
1105     return -1;
1106 }
1107
1108 static GInputStream  *
1109 g_tls_connection_gnutls_get_input_stream (GIOStream *stream)
1110 {
1111   GTlsConnectionGnutls *gnutls = G_TLS_CONNECTION_GNUTLS (stream);
1112
1113   return gnutls->priv->tls_istream;
1114 }
1115
1116 static GOutputStream *
1117 g_tls_connection_gnutls_get_output_stream (GIOStream *stream)
1118 {
1119   GTlsConnectionGnutls *gnutls = G_TLS_CONNECTION_GNUTLS (stream);
1120
1121   return gnutls->priv->tls_ostream;
1122 }
1123
1124 static gboolean
1125 close_internal (GTlsConnectionGnutls  *gnutls,
1126                 gboolean               blocking,
1127                 GCancellable          *cancellable,
1128                 GError               **error)
1129 {
1130   int ret;
1131
1132   /* If we haven't finished the initial handshake yet, there's no
1133    * reason to finish it just so we can close.
1134    */
1135   if (gnutls->priv->handshaking && !gnutls->priv->ever_handshaked)
1136     return TRUE;
1137
1138   if (handshake_in_progress_or_failed (gnutls, blocking, cancellable, error))
1139     return FALSE;
1140
1141   gnutls->priv->closing = TRUE;
1142   BEGIN_GNUTLS_IO (gnutls, blocking, cancellable);
1143   ret = gnutls_bye (gnutls->priv->session, GNUTLS_SHUT_WR);
1144   END_GNUTLS_IO (gnutls, ret, _("Error performing TLS close: %s"), error);
1145   if (ret == 0 || !error || !g_error_matches (*error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK))
1146     gnutls->priv->closing = FALSE;
1147
1148   return ret == 0;
1149 }
1150
1151 static gboolean
1152 g_tls_connection_gnutls_close (GIOStream     *stream,
1153                                GCancellable  *cancellable,
1154                                GError       **error)
1155 {
1156   GTlsConnectionGnutls *gnutls = G_TLS_CONNECTION_GNUTLS (stream);
1157
1158   if (!close_internal (gnutls, TRUE, cancellable, error))
1159     return FALSE;
1160   return g_io_stream_close (gnutls->priv->base_io_stream,
1161                             cancellable, error);
1162 }
1163
1164 typedef struct {
1165   GSimpleAsyncResult *simple;
1166   GCancellable *cancellable;
1167   int io_priority;
1168 } AsyncCloseData;
1169
1170 static void
1171 close_base_stream_cb (GObject      *base_stream,
1172                       GAsyncResult *result,
1173                       gpointer      user_data)
1174 {
1175   gboolean success;
1176   GError *error = NULL;
1177   AsyncCloseData *acd = user_data;
1178
1179   success = g_io_stream_close_finish (G_IO_STREAM (base_stream),
1180                                       result, &error);
1181   if (success)
1182     g_simple_async_result_set_op_res_gboolean (acd->simple, TRUE);
1183   else
1184     {
1185       g_simple_async_result_set_from_error (acd->simple, error);
1186       g_error_free (error);
1187     }
1188
1189   g_simple_async_result_complete (acd->simple);
1190   g_object_unref (acd->simple);
1191   if (acd->cancellable)
1192     g_object_unref (acd->cancellable);
1193   g_slice_free (AsyncCloseData, acd);
1194 }
1195
1196 static gboolean
1197 g_tls_connection_gnutls_close_ready (GObject  *pollable_stream,
1198                                      gpointer  user_data)
1199 {
1200   GTlsConnectionGnutls *gnutls;
1201   AsyncCloseData *acd = user_data;
1202   gboolean success;
1203   GError *error = NULL;
1204
1205   gnutls = G_TLS_CONNECTION_GNUTLS (g_async_result_get_source_object (G_ASYNC_RESULT (acd->simple)));
1206   g_object_unref (gnutls);
1207
1208   success = close_internal (gnutls, FALSE, NULL, &error);
1209   if (!success && g_error_matches (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK))
1210     {
1211       g_error_free (error);
1212       return TRUE;
1213     }
1214
1215   if (error)
1216     {
1217       g_simple_async_result_set_from_error (acd->simple, error);
1218       g_simple_async_result_complete (acd->simple);
1219       g_error_free (error);
1220       g_object_unref (acd->simple);
1221       if (acd->cancellable)
1222         g_object_unref (acd->cancellable);
1223       g_slice_free (AsyncCloseData, acd);
1224     }
1225   else
1226     {
1227       g_io_stream_close_async (gnutls->priv->base_io_stream,
1228                                acd->io_priority, acd->cancellable,
1229                                close_base_stream_cb, acd);
1230     }
1231
1232   return FALSE;
1233 }
1234
1235 static void
1236 g_tls_connection_gnutls_close_async (GIOStream           *stream,
1237                                      int                  io_priority,
1238                                      GCancellable        *cancellable,
1239                                      GAsyncReadyCallback  callback,
1240                                      gpointer             user_data)
1241 {
1242   GTlsConnectionGnutls *gnutls = G_TLS_CONNECTION_GNUTLS (stream);
1243   GSimpleAsyncResult *simple;
1244   gboolean success;
1245   GError *error = NULL;
1246   AsyncCloseData *acd;
1247   GSource *source;
1248
1249   simple = g_simple_async_result_new (G_OBJECT (stream), callback, user_data,
1250                                       g_tls_connection_gnutls_close_async);
1251
1252   success = close_internal (gnutls, FALSE, cancellable, &error);
1253   if (error && !g_error_matches (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK))
1254     {
1255       g_simple_async_result_set_from_error (simple, error);
1256       g_error_free (error);
1257       g_simple_async_result_complete_in_idle (simple);
1258       g_object_unref (simple);
1259     }
1260
1261   if (error)
1262     g_error_free (error);
1263
1264   acd = g_slice_new (AsyncCloseData);
1265   acd->simple = simple;
1266   acd->cancellable = cancellable ? g_object_ref (cancellable) : cancellable;
1267   acd->io_priority = io_priority;
1268
1269   if (success)
1270     {
1271       g_io_stream_close_async (gnutls->priv->base_io_stream,
1272                                io_priority, cancellable,
1273                                close_base_stream_cb, acd);
1274       return;
1275     }
1276
1277   source = g_tls_connection_gnutls_create_source (gnutls, 0, acd->cancellable);
1278   g_source_set_callback (source,
1279                          (GSourceFunc) g_tls_connection_gnutls_close_ready,
1280                          acd, NULL);
1281   g_source_set_priority (source, acd->io_priority);
1282   g_source_attach (source, g_main_context_get_thread_default ());
1283   g_source_unref (source);
1284 }
1285
1286 static gboolean
1287 g_tls_connection_gnutls_close_finish (GIOStream           *stream,
1288                                       GAsyncResult        *result,
1289                                       GError             **error)
1290 {
1291   GSimpleAsyncResult *simple;
1292
1293   g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (stream), g_tls_connection_gnutls_close_async), FALSE);
1294
1295   simple = G_SIMPLE_ASYNC_RESULT (result);
1296
1297   if (g_simple_async_result_propagate_error (simple, error))
1298     return FALSE;
1299
1300   return g_simple_async_result_get_op_res_gboolean (simple);
1301 }