/pidgin/main: 53718d3c53f0: Port sslconn.[ch] to Gio
Mike Ruprecht <[email protected]>
| Newsgroups | gmane.comp.gnome.gaim.cvs |
|---|---|
| Message-ID | <[email protected]> |
Changeset: 53718d3c53f08f3f42bfd0d6fd0a174be840f6f7 Author: Mike Ruprecht <[email protected]> Date: 2016-03-30 01:20 -0500 Branch: purple-ssl-to-gio URL: https://hg.pidgin.im/pidgin/main/rev/53718d3c53f0 Description: Port sslconn.[ch] to Gio This patch ports purple_ssl_* functions to use Gio's GTlsClientConnection internally instead of the libpurple SSL backend plugins. This temporarily breaks manually accepting certificates until the request API is ported and the helper functions implement this functionality. diffstat: libpurple/sslconn.c | 205 +++++++++++++++++++++++++++++++++++++-------------- libpurple/sslconn.h | 6 +- 2 files changed, 152 insertions(+), 59 deletions(-) diffs (truncated from 382 to 300 lines): diff --git a/libpurple/sslconn.c b/libpurple/sslconn.c --- a/libpurple/sslconn.c +++ b/libpurple/sslconn.c @@ -22,11 +22,11 @@ #include "internal.h" -#include "certificate.h" #include "debug.h" #include "plugins.h" #include "request.h" #include "sslconn.h" +#include "tls-certificate.h" static gboolean _ssl_initialized = FALSE; static PurpleSslOps *_ssl_ops = NULL; @@ -34,50 +34,103 @@ static PurpleSslOps *_ssl_ops = NULL; static gboolean ssl_init(void) { - PurplePlugin *plugin; - PurpleSslOps *ops; + return g_tls_backend_supports_tls(g_tls_backend_get_default()); +} - if (_ssl_initialized) - return FALSE; +static void +emit_error(PurpleSslConnection *gsc, int error_code) +{ + if (gsc->error_cb != NULL) + gsc->error_cb(gsc, error_code, gsc->connect_cb_data); +} - plugin = purple_plugins_find_plugin("core-ssl"); +static void +tls_handshake_cb(GObject *source, GAsyncResult *res, gpointer user_data) +{ + PurpleSslConnection *gsc = user_data; + GError *error = NULL; - if (plugin && !purple_plugin_is_loaded(plugin)) - purple_plugin_load(plugin, NULL); + if (!g_tls_connection_handshake_finish(G_TLS_CONNECTION(source), res, + &error)) { + if (g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { + /* Connection already closed/freed. Escape. */ + return; + } else if (g_error_matches(error, G_TLS_ERROR, + G_TLS_ERROR_HANDSHAKE)) { + /* In Gio, a handshake error is because of the cert */ + emit_error(gsc, PURPLE_SSL_CERTIFICATE_INVALID); + } else { + /* Report any other errors as handshake failing */ + emit_error(gsc, PURPLE_SSL_HANDSHAKE_FAILED); + } - ops = purple_ssl_get_ops(); - if ((ops == NULL) || (ops->init == NULL) || (ops->uninit == NULL) || - (ops->connectfunc == NULL) || (ops->close == NULL) || - (ops->read == NULL) || (ops->write == NULL)) - { - return FALSE; + purple_ssl_close(gsc); + return; } - return (_ssl_initialized = ops->init()); + gsc->connect_cb(gsc->connect_cb_data, gsc, PURPLE_INPUT_READ); +} + +static void +tls_connect(PurpleSslConnection *gsc) +{ + GSocket *socket; + GSocketConnection *conn; + GSocketConnectable *identity; + GIOStream *tls_conn; + GError *error = NULL; + + g_return_if_fail(gsc->conn == NULL); + + socket = g_socket_new_from_fd(gsc->fd, &error); + if (socket == NULL) { + emit_error(gsc, PURPLE_SSL_CONNECT_FAILED); + purple_ssl_close(gsc); + return; + } + + conn = g_socket_connection_factory_create_connection(socket); + g_object_unref(socket); + + identity = g_network_address_new(gsc->host, gsc->port); + tls_conn = g_tls_client_connection_new(G_IO_STREAM(conn), identity, + &error); + g_object_unref(identity); + g_object_unref(conn); + + if (tls_conn == NULL) { + emit_error(gsc, PURPLE_SSL_CONNECT_FAILED); + purple_ssl_close(gsc); + return; + } + + gsc->conn = G_TLS_CONNECTION(tls_conn); + gsc->cancellable = g_cancellable_new(); + + purple_tls_certificate_attach_to_tls_connection(gsc->conn); + + g_tls_connection_handshake_async(gsc->conn, G_PRIORITY_DEFAULT, + gsc->cancellable, tls_handshake_cb, gsc); } static void purple_ssl_connect_cb(gpointer data, gint source, const gchar *error_message) { PurpleSslConnection *gsc; - PurpleSslOps *ops; gsc = data; gsc->connect_data = NULL; if (source < 0) { - if (gsc->error_cb != NULL) - gsc->error_cb(gsc, PURPLE_SSL_CONNECT_FAILED, gsc->connect_cb_data); - + emit_error(gsc, PURPLE_SSL_CONNECT_FAILED); purple_ssl_close(gsc); return; } gsc->fd = source; - ops = purple_ssl_get_ops(); - ops->connectfunc(gsc); + tls_connect(gsc); } PurpleSslConnection * @@ -115,9 +168,6 @@ purple_ssl_connect_with_ssl_cn(PurpleAcc gsc->connect_cb = func; gsc->error_cb = error_func; - /* TODO: Move this elsewhere */ - gsc->verifier = purple_certificate_find_verifier("x509","tls_cached"); - gsc->connect_data = purple_proxy_connect(NULL, account, host, port, purple_ssl_connect_cb, gsc); if (gsc->connect_data == NULL) @@ -131,33 +181,45 @@ purple_ssl_connect_with_ssl_cn(PurpleAcc return (PurpleSslConnection *)gsc; } -static void -recv_cb(gpointer data, gint source, PurpleInputCondition cond) +static gboolean +recv_cb(GObject *source, gpointer data) { PurpleSslConnection *gsc = data; - gsc->recv_cb(gsc->recv_cb_data, gsc, cond); + gsc->recv_cb(gsc->recv_cb_data, gsc, PURPLE_INPUT_READ); + + return TRUE; } void purple_ssl_input_add(PurpleSslConnection *gsc, PurpleSslInputFunction func, void *data) { + GInputStream *input; + GSource *source; + g_return_if_fail(func != NULL); + g_return_if_fail(gsc->conn != NULL); purple_ssl_input_remove(gsc); gsc->recv_cb_data = data; gsc->recv_cb = func; - gsc->inpa = purple_input_add(gsc->fd, PURPLE_INPUT_READ, recv_cb, gsc); + input = g_io_stream_get_input_stream(G_IO_STREAM(gsc->conn)); + /* Pass NULL for cancellable as we don't want it notified on cancel */ + source = g_pollable_input_stream_create_source( + G_POLLABLE_INPUT_STREAM(input), NULL); + g_source_set_callback(source, (GSourceFunc)recv_cb, gsc, NULL); + gsc->inpa = g_source_attach(source, NULL); + g_source_unref(source); } void purple_ssl_input_remove(PurpleSslConnection *gsc) { if (gsc->inpa > 0) { - purple_input_remove(gsc->inpa); + g_source_remove(gsc->inpa); gsc->inpa = 0; } } @@ -186,7 +248,6 @@ purple_ssl_connect_with_host_fd(PurpleAc void *data) { PurpleSslConnection *gsc; - PurpleSslOps *ops; g_return_val_if_fail(fd != -1, NULL); g_return_val_if_fail(func != NULL, NULL); @@ -205,13 +266,9 @@ purple_ssl_connect_with_host_fd(PurpleAc gsc->fd = fd; if(host) gsc->host = g_strdup(host); + gsc->cancellable = g_cancellable_new(); - /* TODO: Move this elsewhere */ - gsc->verifier = purple_certificate_find_verifier("x509","tls_cached"); - - - ops = purple_ssl_get_ops(); - ops->connectfunc(gsc); + tls_connect(gsc); return (PurpleSslConnection *)gsc; } @@ -219,24 +276,30 @@ purple_ssl_connect_with_host_fd(PurpleAc void purple_ssl_close(PurpleSslConnection *gsc) { - PurpleSslOps *ops; - g_return_if_fail(gsc != NULL); purple_request_close_with_handle(gsc); purple_notify_close_with_handle(gsc); - ops = purple_ssl_get_ops(); - (ops->close)(gsc); - if (gsc->connect_data != NULL) purple_proxy_connect_cancel(gsc->connect_data); if (gsc->inpa > 0) purple_input_remove(gsc->inpa); - if (gsc->fd >= 0) - close(gsc->fd); + /* Stop any pending operations */ + if (G_IS_CANCELLABLE(gsc->cancellable)) { + g_cancellable_cancel(gsc->cancellable); + g_clear_object(&gsc->cancellable); + } + + if (gsc->conn != NULL) { + /* Close the stream. Shouldn't take long and it can't + * be further cancelled so don't pass a cancellable + */ + g_io_stream_close(G_IO_STREAM(gsc->conn), NULL, NULL); + g_clear_object(&gsc->conn); + } g_free(gsc->host); g_free(gsc); @@ -245,38 +308,71 @@ purple_ssl_close(PurpleSslConnection *gs size_t purple_ssl_read(PurpleSslConnection *gsc, void *data, size_t len) { - PurpleSslOps *ops; + GInputStream *input; + gssize outlen; + GError *error = NULL; g_return_val_if_fail(gsc != NULL, 0); g_return_val_if_fail(data != NULL, 0); g_return_val_if_fail(len > 0, 0); + g_return_val_if_fail(gsc->conn != NULL, 0); - ops = purple_ssl_get_ops(); - return (ops->read)(gsc, data, len); + input = g_io_stream_get_input_stream(G_IO_STREAM(gsc->conn)); + outlen = g_pollable_input_stream_read_nonblocking( + G_POLLABLE_INPUT_STREAM(input), data, len, + gsc->cancellable, &error); + + if (outlen < 0) { + if (outlen == G_IO_ERROR_WOULD_BLOCK) { + errno = EAGAIN; + } + + g_clear_error(&error); + } + + return outlen; } size_t purple_ssl_write(PurpleSslConnection *gsc, const void *data, size_t len) { - PurpleSslOps *ops; + GOutputStream *output; _______________________________________________ Commits mailing list [email protected] https://pidgin.im/cgi-bin/mailman/listinfo/commits