X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=gio%2Fgtlsinteraction.c;h=ba94fe10e22a0be09283b28637c60685725dd4c6;hb=174ebaefcc2b1b94f4a628e60f150b7209230dbf;hp=196b055b7cbddce31a29afc6b74dd840a1fc7554;hpb=32747def4bb4cce7cfc4f0f8ba8560392ec9ad3d;p=platform%2Fupstream%2Fglib.git diff --git a/gio/gtlsinteraction.c b/gio/gtlsinteraction.c index 196b055..ba94fe1 100644 --- a/gio/gtlsinteraction.c +++ b/gio/gtlsinteraction.c @@ -13,9 +13,7 @@ * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General - * Public License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place, Suite 330, - * Boston, MA 02111-1307, USA. + * Public License along with this library; if not, see . * * Author: Stef Walter */ @@ -24,6 +22,8 @@ #include +#include "gtlscertificate.h" +#include "gtlsconnection.h" #include "gtlsinteraction.h" #include "gtlspassword.h" #include "gasyncresult.h" @@ -182,10 +182,59 @@ invoke_closure_wait_and_free (InvokeClosure *closure, return result; } +static GTlsInteractionResult +invoke_closure_complete_and_free (GTlsInteraction *interaction, + InvokeClosure *closure, + GError **error) +{ + GTlsInteractionResult result; + gboolean complete; + + /* + * Handle the case where we've been called from within the main context + * or in the case where the main context is not running. This approximates + * the behavior of a modal dialog. + */ + if (g_main_context_acquire (interaction->priv->context)) + { + for (;;) + { + g_mutex_lock (&closure->mutex); + complete = closure->complete; + g_mutex_unlock (&closure->mutex); + if (complete) + break; + g_main_context_iteration (interaction->priv->context, TRUE); + } + + g_main_context_release (interaction->priv->context); + + if (closure->error) + { + g_propagate_error (error, closure->error); + closure->error = NULL; + } + + result = closure->result; + invoke_closure_free (closure); + } + + /* + * Handle the case where we're in a different thread than the main + * context and a main loop is running. + */ + else + { + result = invoke_closure_wait_and_free (closure, error); + } + + return result; +} + static void g_tls_interaction_init (GTlsInteraction *interaction) { - interaction->priv = g_tls_interaction_get_private (interaction); + interaction->priv = g_tls_interaction_get_instance_private (interaction); interaction->priv->context = g_main_context_ref_thread_default (); } @@ -231,9 +280,9 @@ on_invoke_ask_password_sync (gpointer user_data) } static void -on_async_as_sync_complete (GObject *source, - GAsyncResult *result, - gpointer user_data) +on_ask_password_complete (GObject *source, + GAsyncResult *result, + gpointer user_data) { InvokeClosure *closure = user_data; GTlsInteractionClass *klass; @@ -266,7 +315,7 @@ on_invoke_ask_password_async_as_sync (gpointer user_data) klass->ask_password_async (closure->interaction, G_TLS_PASSWORD (closure->argument), closure->cancellable, - on_async_as_sync_complete, + on_ask_password_complete, closure); /* Note that we've used these */ @@ -318,17 +367,16 @@ g_tls_interaction_invoke_ask_password (GTlsInteraction *interaction, GTlsInteractionResult result; InvokeClosure *closure; GTlsInteractionClass *klass; - gboolean complete; g_return_val_if_fail (G_IS_TLS_INTERACTION (interaction), G_TLS_INTERACTION_UNHANDLED); g_return_val_if_fail (G_IS_TLS_PASSWORD (password), G_TLS_INTERACTION_UNHANDLED); g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), G_TLS_INTERACTION_UNHANDLED); - closure = invoke_closure_new (interaction, G_OBJECT (password), cancellable); - klass = G_TLS_INTERACTION_GET_CLASS (interaction); + if (klass->ask_password) { + closure = invoke_closure_new (interaction, G_OBJECT (password), cancellable); g_main_context_invoke (interaction->priv->context, on_invoke_ask_password_sync, closure); result = invoke_closure_wait_and_free (closure, error); @@ -336,57 +384,21 @@ g_tls_interaction_invoke_ask_password (GTlsInteraction *interaction, else if (klass->ask_password_async) { g_return_val_if_fail (klass->ask_password_finish, G_TLS_INTERACTION_UNHANDLED); + + closure = invoke_closure_new (interaction, G_OBJECT (password), cancellable); g_main_context_invoke (interaction->priv->context, on_invoke_ask_password_async_as_sync, closure); - /* - * Handle the case where we've been called from within the main context - * or in the case where the main context is not running. This approximates - * the behavior of a modal dialog. - */ - if (g_main_context_acquire (interaction->priv->context)) - { - for (;;) - { - g_mutex_lock (&closure->mutex); - complete = closure->complete; - g_mutex_unlock (&closure->mutex); - if (complete) - break; - g_main_context_iteration (interaction->priv->context, TRUE); - } - - g_main_context_release (interaction->priv->context); - - if (closure->error) - { - g_propagate_error (error, closure->error); - closure->error = NULL; - } - - result = closure->result; - invoke_closure_free (closure); - } - - /* - * Handle the case where we're in a different thread than the main - * context and a main loop is running. - */ - else - { - result = invoke_closure_wait_and_free (closure, error); - } + result = invoke_closure_complete_and_free (interaction, closure, error); } else { result = G_TLS_INTERACTION_UNHANDLED; - invoke_closure_free (closure); } return result; } - /** * g_tls_interaction_ask_password: * @interaction: a #GTlsInteraction object @@ -531,3 +543,295 @@ g_tls_interaction_ask_password_finish (GTlsInteraction *interaction, return g_task_propagate_int (G_TASK (result), error); } } + +static gboolean +on_invoke_request_certificate_sync (gpointer user_data) +{ + InvokeClosure *closure = user_data; + GTlsInteractionClass *klass; + + g_mutex_lock (&closure->mutex); + + klass = G_TLS_INTERACTION_GET_CLASS (closure->interaction); + g_assert (klass->request_certificate != NULL); + + closure->result = klass->request_certificate (closure->interaction, + G_TLS_CONNECTION (closure->argument), + 0, + closure->cancellable, + &closure->error); + + closure->complete = TRUE; + g_cond_signal (&closure->cond); + g_mutex_unlock (&closure->mutex); + + return FALSE; /* don't call again */ +} + +static void +on_request_certificate_complete (GObject *source, + GAsyncResult *result, + gpointer user_data) +{ + InvokeClosure *closure = user_data; + GTlsInteractionClass *klass; + + g_mutex_lock (&closure->mutex); + + klass = G_TLS_INTERACTION_GET_CLASS (closure->interaction); + g_assert (klass->request_certificate_finish != NULL); + + closure->result = klass->request_certificate_finish (closure->interaction, + result, &closure->error); + + closure->complete = TRUE; + g_cond_signal (&closure->cond); + g_mutex_unlock (&closure->mutex); +} + +static gboolean +on_invoke_request_certificate_async_as_sync (gpointer user_data) +{ + InvokeClosure *closure = user_data; + GTlsInteractionClass *klass; + + g_mutex_lock (&closure->mutex); + + klass = G_TLS_INTERACTION_GET_CLASS (closure->interaction); + g_assert (klass->request_certificate_async); + + klass->request_certificate_async (closure->interaction, + G_TLS_CONNECTION (closure->argument), 0, + closure->cancellable, + on_request_certificate_complete, + closure); + + /* Note that we've used these */ + closure->callback = NULL; + closure->user_data = NULL; + + g_mutex_unlock (&closure->mutex); + + return FALSE; /* don't call again */ +} + +/** + * g_tls_interaction_invoke_request_certificate: + * @interaction: a #GTlsInteraction object + * @connection: a #GTlsConnection object + * @flags: flags providing more information about the request + * @cancellable: an optional #GCancellable cancellation object + * @error: an optional location to place an error on failure + * + * Invoke the interaction to ask the user to choose a certificate to + * use with the connection. It invokes this interaction in the main + * loop, specifically the #GMainContext returned by + * g_main_context_get_thread_default() when the interaction is + * created. This is called by called by #GTlsConnection when the peer + * requests a certificate during the handshake. + * + * Derived subclasses usually implement a certificate selector, + * although they may also choose to provide a certificate from + * elsewhere. Alternatively the user may abort this certificate + * request, which may or may not abort the TLS connection. + * + * The implementation can either be a synchronous (eg: modal dialog) or an + * asynchronous one (eg: modeless dialog). This function will take care of + * calling which ever one correctly. + * + * If the interaction is cancelled by the cancellation object, or by the + * user then %G_TLS_INTERACTION_FAILED will be returned with an error that + * contains a %G_IO_ERROR_CANCELLED error code. Certain implementations may + * not support immediate cancellation. + * + * Returns: The status of the certificate request interaction. + * + * Since: 2.40 + */ +GTlsInteractionResult +g_tls_interaction_invoke_request_certificate (GTlsInteraction *interaction, + GTlsConnection *connection, + GTlsCertificateRequestFlags flags, + GCancellable *cancellable, + GError **error) +{ + GTlsInteractionResult result; + InvokeClosure *closure; + GTlsInteractionClass *klass; + + g_return_val_if_fail (G_IS_TLS_INTERACTION (interaction), G_TLS_INTERACTION_UNHANDLED); + g_return_val_if_fail (G_IS_TLS_CONNECTION (connection), G_TLS_INTERACTION_UNHANDLED); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), G_TLS_INTERACTION_UNHANDLED); + + klass = G_TLS_INTERACTION_GET_CLASS (interaction); + + if (klass->request_certificate) + { + closure = invoke_closure_new (interaction, G_OBJECT (connection), cancellable); + g_main_context_invoke (interaction->priv->context, + on_invoke_request_certificate_sync, closure); + result = invoke_closure_wait_and_free (closure, error); + } + else if (klass->request_certificate_async) + { + g_return_val_if_fail (klass->request_certificate_finish, G_TLS_INTERACTION_UNHANDLED); + + closure = invoke_closure_new (interaction, G_OBJECT (connection), cancellable); + g_main_context_invoke (interaction->priv->context, + on_invoke_request_certificate_async_as_sync, closure); + + result = invoke_closure_complete_and_free (interaction, closure, error); + } + else + { + result = G_TLS_INTERACTION_UNHANDLED; + } + + return result; +} + +/** + * g_tls_interaction_request_certificate: + * @interaction: a #GTlsInteraction object + * @connection: a #GTlsConnection object + * @flags: flags providing more information about the request + * @cancellable: an optional #GCancellable cancellation object + * @error: an optional location to place an error on failure + * + * Run synchronous interaction to ask the user to choose a certificate to use + * with the connection. In general, g_tls_interaction_invoke_request_certificate() + * should be used instead of this function. + * + * Derived subclasses usually implement a certificate selector, although they may + * also choose to provide a certificate from elsewhere. Alternatively the user may + * abort this certificate request, which will usually abort the TLS connection. + * + * If %G_TLS_INTERACTION_HANDLED is returned, then the #GTlsConnection + * passed to g_tls_interaction_request_certificate() will have had its + * #GTlsConnection:certificate filled in. + * + * If the interaction is cancelled by the cancellation object, or by the + * user then %G_TLS_INTERACTION_FAILED will be returned with an error that + * contains a %G_IO_ERROR_CANCELLED error code. Certain implementations may + * not support immediate cancellation. + * + * Returns: The status of the request certificate interaction. + * + * Since: 2.40 + */ +GTlsInteractionResult +g_tls_interaction_request_certificate (GTlsInteraction *interaction, + GTlsConnection *connection, + GTlsCertificateRequestFlags flags, + GCancellable *cancellable, + GError **error) +{ + GTlsInteractionClass *klass; + + g_return_val_if_fail (G_IS_TLS_INTERACTION (interaction), G_TLS_INTERACTION_UNHANDLED); + g_return_val_if_fail (G_IS_TLS_CONNECTION (connection), G_TLS_INTERACTION_UNHANDLED); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), G_TLS_INTERACTION_UNHANDLED); + + klass = G_TLS_INTERACTION_GET_CLASS (interaction); + if (klass->request_certificate) + return (klass->request_certificate) (interaction, connection, flags, cancellable, error); + else + return G_TLS_INTERACTION_UNHANDLED; +} + +/** + * g_tls_interaction_request_certificate_async: + * @interaction: a #GTlsInteraction object + * @connection: a #GTlsConnection object + * @flags: flags providing more information about the request + * @cancellable: an optional #GCancellable cancellation object + * @callback: (allow-none): will be called when the interaction completes + * @user_data: (allow-none): data to pass to the @callback + * + * Run asynchronous interaction to ask the user for a certificate to use with + * the connection. In general, g_tls_interaction_invoke_request_certificate() should + * be used instead of this function. + * + * Derived subclasses usually implement a certificate selector, although they may + * also choose to provide a certificate from elsewhere. @callback will be called + * when the operation completes. Alternatively the user may abort this certificate + * request, which will usually abort the TLS connection. + * + * Since: 2.40 + */ +void +g_tls_interaction_request_certificate_async (GTlsInteraction *interaction, + GTlsConnection *connection, + GTlsCertificateRequestFlags flags, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GTlsInteractionClass *klass; + GTask *task; + + g_return_if_fail (G_IS_TLS_INTERACTION (interaction)); + g_return_if_fail (G_IS_TLS_CONNECTION (connection)); + g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); + + klass = G_TLS_INTERACTION_GET_CLASS (interaction); + if (klass->request_certificate_async) + { + g_return_if_fail (klass->request_certificate_finish); + (klass->request_certificate_async) (interaction, connection, flags, + cancellable, callback, user_data); + } + else + { + task = g_task_new (interaction, cancellable, callback, user_data); + g_task_set_source_tag (task, g_tls_interaction_request_certificate_async); + g_task_return_int (task, G_TLS_INTERACTION_UNHANDLED); + g_object_unref (task); + } +} + +/** + * g_tls_interaction_request_certificate_finish: + * @interaction: a #GTlsInteraction object + * @result: the result passed to the callback + * @error: an optional location to place an error on failure + * + * Complete an request certificate user interaction request. This should be once + * the g_tls_interaction_request_certificate_async() completion callback is called. + * + * If %G_TLS_INTERACTION_HANDLED is returned, then the #GTlsConnection + * passed to g_tls_interaction_request_certificate_async() will have had its + * #GTlsConnection:certificate filled in. + * + * If the interaction is cancelled by the cancellation object, or by the + * user then %G_TLS_INTERACTION_FAILED will be returned with an error that + * contains a %G_IO_ERROR_CANCELLED error code. + * + * Returns: The status of the request certificate interaction. + * + * Since: 2.40 + */ +GTlsInteractionResult +g_tls_interaction_request_certificate_finish (GTlsInteraction *interaction, + GAsyncResult *result, + GError **error) +{ + GTlsInteractionClass *klass; + + g_return_val_if_fail (G_IS_TLS_INTERACTION (interaction), G_TLS_INTERACTION_UNHANDLED); + g_return_val_if_fail (G_IS_ASYNC_RESULT (result), G_TLS_INTERACTION_UNHANDLED); + + klass = G_TLS_INTERACTION_GET_CLASS (interaction); + if (klass->request_certificate_finish) + { + g_return_val_if_fail (klass->request_certificate_async != NULL, G_TLS_INTERACTION_UNHANDLED); + + return (klass->request_certificate_finish) (interaction, result, error); + } + else + { + g_return_val_if_fail (g_async_result_is_tagged (result, g_tls_interaction_request_certificate_async), G_TLS_INTERACTION_UNHANDLED); + + return g_task_propagate_int (G_TASK (result), error); + } +}