From 97bacf3057b7c45c29a6d025c67a6dd588144e05 Mon Sep 17 00:00:00 2001 From: Dan Winship Date: Thu, 12 Nov 2009 19:44:27 -0500 Subject: [PATCH] SoupSocket: port to GSocketConnection/GTlsConnection and remove libsoup's built-in TLS support, which is no longer needed --- README | 2 +- configure.ac | 40 +-- libsoup-2.4.pc.in | 2 +- libsoup/Makefile.am | 10 +- libsoup/soup-address.h | 2 - libsoup/soup-connection.h | 2 - libsoup/soup-gnutls.c | 705 ---------------------------------------- libsoup/soup-message-io.c | 2 +- libsoup/soup-message-queue.h | 3 - libsoup/soup-nossl.c | 91 ------ libsoup/soup-password-manager.h | 1 - libsoup/soup-portability.h | 2 +- libsoup/soup-proxy-resolver.h | 1 - libsoup/soup-socket.c | 598 +++++++++++++--------------------- libsoup/soup-socket.h | 1 - libsoup/soup-ssl.c | 143 ++++++++ libsoup/soup-ssl.h | 22 +- libsoup/soup-status.c | 4 - libsoup/soup-types.h | 3 +- tests/Makefile.am | 9 +- tests/proxy-test.c | 6 - tests/ssl-test.c | 357 -------------------- tests/timeout-test.c | 4 +- 23 files changed, 382 insertions(+), 1628 deletions(-) delete mode 100644 libsoup/soup-gnutls.c delete mode 100644 libsoup/soup-nossl.c create mode 100644 libsoup/soup-ssl.c delete mode 100644 tests/ssl-test.c diff --git a/README b/README index bf3b70a..8baf635 100644 --- a/README +++ b/README @@ -4,7 +4,7 @@ and the glib main loop, to integrate well with GNOME applications. Features: * Both asynchronous (GMainLoop and callback-based) and synchronous APIs * Automatically caches connections - * SSL Support using GnuTLS + * SSL support * Proxy support, including authentication and SSL tunneling * Client support for Digest, NTLM, and Basic authentication * Server support for Digest and Basic authentication diff --git a/configure.ac b/configure.ac index 5f47501..948651d 100644 --- a/configure.ac +++ b/configure.ac @@ -72,9 +72,9 @@ dnl *********************** dnl *** Checks for glib *** dnl *********************** -AM_PATH_GLIB_2_0(2.21.3,,,gobject gthread gio) +AM_PATH_GLIB_2_0(2.27.4,,,gobject gthread gio) if test "$GLIB_LIBS" = ""; then - AC_MSG_ERROR(GLIB 2.21.3 or later is required to build libsoup) + AC_MSG_ERROR(GLIB 2.27.4 or later is required to build libsoup) fi GLIB_CFLAGS="$GLIB_CFLAGS -DG_DISABLE_SINGLE_INCLUDES" @@ -106,39 +106,6 @@ AC_CHECK_FUNCS(gmtime_r) AC_CHECK_FUNCS(mmap) AC_CHECK_FUNC(socket, , AC_CHECK_LIB(socket, socket)) -dnl ********************************** -dnl *** SSL Library check (GnuTLS) *** -dnl ********************************** - -AC_ARG_ENABLE(ssl, - AS_HELP_STRING([--disable-ssl], [Disable SSL/TLS support (not recommended)]),, - enable_ssl=auto) - -have_ssl=no -if test "$enable_ssl" != "no"; then - PKG_CHECK_MODULES(LIBGNUTLS, gnutls >= 2.1.7, - [AM_PATH_LIBGCRYPT([], have_ssl=yes, have_ssl=no)], have_ssl=no) -fi -if test "$have_ssl" = "yes"; then - AC_DEFINE(HAVE_SSL, 1, [Defined if you have SSL support]) - SSL_REQUIREMENT="gnutls" -else - if test "$enable_ssl" = "no"; then - AC_MSG_WARN(Disabling SSL support); - else - AC_MSG_ERROR([Could not configure SSL support. -Pass "--disable-ssl" if you really want to build without SSL support]); - fi -fi - -AC_SUBST(LIBGNUTLS_CFLAGS) -AC_SUBST(LIBGNUTLS_LIBS) -AC_SUBST(SSL_REQUIREMENT) - -dnl This is not supposed to be conditional, but... -AM_CONDITIONAL(HAVE_SSL, test $enable_ssl != no) - - dnl ********************* dnl *** GNOME support *** dnl ********************* @@ -256,9 +223,6 @@ dnl *** Stuff for regression tests dnl ****************************** AC_MSG_NOTICE([checking for programs needed for regression tests]) MISSING_REGRESSION_TEST_PACKAGES="" -if test $have_ssl = "no"; then - MISSING_REGRESSION_TEST_PACKAGES=" gnutls" -fi AC_ARG_WITH(apache-httpd, AS_HELP_STRING([--with-apache-httpd], [Path to apache httpd (for tests)]), diff --git a/libsoup-2.4.pc.in b/libsoup-2.4.pc.in index 7df813c..1394939 100644 --- a/libsoup-2.4.pc.in +++ b/libsoup-2.4.pc.in @@ -7,6 +7,6 @@ Name: libsoup Description: a glib-based HTTP library Version: @VERSION@ Requires: glib-2.0 gobject-2.0 gio-2.0 -Requires.private: libxml-2.0 @SSL_REQUIREMENT@ +Requires.private: libxml-2.0 Libs: -L${libdir} -lsoup-2.4 Cflags: -I${includedir}/libsoup-2.4 diff --git a/libsoup/Makefile.am b/libsoup/Makefile.am index 4278f3d..38c0a38 100644 --- a/libsoup/Makefile.am +++ b/libsoup/Makefile.am @@ -14,9 +14,7 @@ INCLUDES = \ $(GCONF_CFLAGS) \ $(LIBPROXY_CFLAGS) \ $(SQLITE_CFLAGS) \ - $(GNOME_KEYRING_CFLAGS) \ - $(LIBGCRYPT_CFLAGS) \ - $(LIBGNUTLS_CFLAGS) + $(GNOME_KEYRING_CFLAGS) MARSHAL_GENERATED = soup-marshal.c soup-marshal.h MKENUMS_GENERATED = soup-enum-types.c soup-enum-types.h @@ -100,9 +98,6 @@ libsoup_2_4_la_LIBADD = \ $(GLIB_LIBS) \ $(XML_LIBS) \ -lz \ - $(LIBGNUTLS_LIBS_STATIC) \ - $(LIBGNUTLS_LIBS) \ - $(LIBGCRYPT_LIBS) \ $(LIBWS2_32) libsoup_2_4_la_SOURCES = \ @@ -135,7 +130,6 @@ libsoup_2_4_la_SOURCES = \ soup-cookie-jar-text.c \ soup-date.c \ soup-form.c \ - soup-gnutls.c \ soup-headers.c \ soup-logger.c \ soup-message.c \ @@ -150,7 +144,6 @@ libsoup_2_4_la_SOURCES = \ soup-method.c \ soup-misc.c \ soup-multipart.c \ - soup-nossl.c \ soup-password-manager.c \ soup-path-map.h \ soup-path-map.c \ @@ -166,6 +159,7 @@ libsoup_2_4_la_SOURCES = \ soup-session-sync.c \ soup-socket.c \ soup-ssl.h \ + soup-ssl.c \ soup-status.c \ soup-uri.c \ soup-value-utils.c \ diff --git a/libsoup/soup-address.h b/libsoup/soup-address.h index 15c66fd..a7023cb 100644 --- a/libsoup/soup-address.h +++ b/libsoup/soup-address.h @@ -8,8 +8,6 @@ #include -#include - #include #include diff --git a/libsoup/soup-connection.h b/libsoup/soup-connection.h index 629676b..ebdf9bc 100644 --- a/libsoup/soup-connection.h +++ b/libsoup/soup-connection.h @@ -6,8 +6,6 @@ #ifndef SOUP_CONNECTION_H #define SOUP_CONNECTION_H 1 -#include - #include "soup-types.h" #include "soup-message-private.h" #include "soup-misc.h" diff --git a/libsoup/soup-gnutls.c b/libsoup/soup-gnutls.c deleted file mode 100644 index 0b57f28..0000000 --- a/libsoup/soup-gnutls.c +++ /dev/null @@ -1,705 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * soup-gnutls.c - * - * Copyright (C) 2003-2006, Novell, Inc. - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#ifdef HAVE_SSL - -#include -#include -#include -#include -#include - -#include - -#ifndef G_OS_WIN32 -#include -#endif - -#include -#include -#include - -#include "soup-ssl.h" -#include "soup-misc.h" - -/** - * soup_ssl_supported: - * - * Can be used to test if libsoup was compiled with ssl support. - **/ -const gboolean soup_ssl_supported = TRUE; - -#define DH_BITS 1024 - -struct SoupSSLCredentials { - gnutls_certificate_credentials creds; - gboolean have_ca_file; -}; - -typedef struct { - GIOChannel channel; - GIOChannel *real_sock; - int sockfd; - gboolean non_blocking, eagain; - gnutls_session session; - SoupSSLCredentials *creds; - char *hostname; - gboolean established; - SoupSSLType type; -} SoupGNUTLSChannel; - -static gboolean -verify_certificate (gnutls_session session, const char *hostname, GError **err) -{ - int status; - - status = gnutls_certificate_verify_peers (session); - - if (status == GNUTLS_E_NO_CERTIFICATE_FOUND) { - g_set_error (err, SOUP_SSL_ERROR, - SOUP_SSL_ERROR_CERTIFICATE, - "No SSL certificate was sent."); - return FALSE; - } - - if (status & GNUTLS_CERT_INVALID || -#ifdef GNUTLS_CERT_NOT_TRUSTED - status & GNUTLS_CERT_NOT_TRUSTED || -#endif - status & GNUTLS_CERT_REVOKED) - { - g_set_error (err, SOUP_SSL_ERROR, - SOUP_SSL_ERROR_CERTIFICATE, - "The SSL certificate is not trusted."); - return FALSE; - } - - if (gnutls_certificate_expiration_time_peers (session) < time (0)) { - g_set_error (err, SOUP_SSL_ERROR, - SOUP_SSL_ERROR_CERTIFICATE, - "The SSL certificate has expired."); - return FALSE; - } - - if (gnutls_certificate_activation_time_peers (session) > time (0)) { - g_set_error (err, SOUP_SSL_ERROR, - SOUP_SSL_ERROR_CERTIFICATE, - "The SSL certificate is not yet activated."); - return FALSE; - } - - if (gnutls_certificate_type_get (session) == GNUTLS_CRT_X509) { - const gnutls_datum* cert_list; - guint cert_list_size; - gnutls_x509_crt cert; - - if (gnutls_x509_crt_init (&cert) < 0) { - g_set_error (err, SOUP_SSL_ERROR, - SOUP_SSL_ERROR_CERTIFICATE, - "Error initializing SSL certificate."); - return FALSE; - } - - cert_list = gnutls_certificate_get_peers ( - session, &cert_list_size); - - if (cert_list == NULL) { - gnutls_x509_crt_deinit (cert); - g_set_error (err, SOUP_SSL_ERROR, - SOUP_SSL_ERROR_CERTIFICATE, - "No SSL certificate was found."); - return FALSE; - } - - if (gnutls_x509_crt_import (cert, &cert_list[0], - GNUTLS_X509_FMT_DER) < 0) { - gnutls_x509_crt_deinit (cert); - g_set_error (err, SOUP_SSL_ERROR, - SOUP_SSL_ERROR_CERTIFICATE, - "The SSL certificate could not be parsed."); - return FALSE; - } - - if (!gnutls_x509_crt_check_hostname (cert, hostname)) { - gnutls_x509_crt_deinit (cert); - g_set_error (err, SOUP_SSL_ERROR, - SOUP_SSL_ERROR_CERTIFICATE, - "The SSL certificate does not match the hostname."); - return FALSE; - } - - gnutls_x509_crt_deinit (cert); - } - - return TRUE; -} - -static GIOStatus -do_handshake (SoupGNUTLSChannel *chan, GError **err) -{ - int result; - -again: - result = gnutls_handshake (chan->session); - - if (result == GNUTLS_E_AGAIN || result == GNUTLS_E_INTERRUPTED) { - if (chan->non_blocking) { - g_set_error (err, SOUP_SSL_ERROR, - (gnutls_record_get_direction (chan->session) ? - SOUP_SSL_ERROR_HANDSHAKE_NEEDS_WRITE : - SOUP_SSL_ERROR_HANDSHAKE_NEEDS_READ), - "Handshaking..."); - return G_IO_STATUS_AGAIN; - } else - goto again; - } - - if (result < 0) { - g_set_error (err, SOUP_SSL_ERROR, - SOUP_SSL_ERROR_HANDSHAKE_FAILED, - "SSL handshake failed: %s", - gnutls_strerror (result)); - return G_IO_STATUS_ERROR; - } - - chan->established = TRUE; - - if (chan->type == SOUP_SSL_TYPE_CLIENT && chan->creds->have_ca_file && - !verify_certificate (chan->session, chan->hostname, err)) - return G_IO_STATUS_ERROR; - - return G_IO_STATUS_NORMAL; -} - -static GIOStatus -soup_gnutls_read (GIOChannel *channel, - gchar *buf, - gsize count, - gsize *bytes_read, - GError **err) -{ - SoupGNUTLSChannel *chan = (SoupGNUTLSChannel *) channel; - gint result; - - *bytes_read = 0; - -again: - if (!chan->established) { - result = do_handshake (chan, err); - - if (result == G_IO_STATUS_AGAIN || - result == G_IO_STATUS_ERROR) - return result; - } - - result = gnutls_record_recv (chan->session, buf, count); - - if (result == GNUTLS_E_REHANDSHAKE) { - chan->established = FALSE; - goto again; - } - - if (result == GNUTLS_E_INTERRUPTED || result == GNUTLS_E_AGAIN) { - if (chan->non_blocking || chan->eagain) - return G_IO_STATUS_AGAIN; - else - goto again; - } - - if (result == GNUTLS_E_UNEXPECTED_PACKET_LENGTH) { - /* This means the connection was either corrupted or - * interrupted. One particular thing that it can mean - * is that the remote end closed the connection - * abruptly without doing a proper TLS Close. There - * are security reasons why it's bad to treat this as - * not-an-error, but for compatibility reasons (eg, - * bug 577386) we kinda have to. And it's not like - * we're very secure anyway. - */ - return G_IO_STATUS_EOF; - } - - if (result < 0) { - g_set_error (err, G_IO_CHANNEL_ERROR, - G_IO_CHANNEL_ERROR_FAILED, - "Received corrupted data"); - return G_IO_STATUS_ERROR; - } else { - *bytes_read = result; - - return (result > 0) ? G_IO_STATUS_NORMAL : G_IO_STATUS_EOF; - } -} - -static GIOStatus -soup_gnutls_write (GIOChannel *channel, - const gchar *buf, - gsize count, - gsize *bytes_written, - GError **err) -{ - SoupGNUTLSChannel *chan = (SoupGNUTLSChannel *) channel; - gint result; - - *bytes_written = 0; - -again: - if (!chan->established) { - result = do_handshake (chan, err); - - if (result == G_IO_STATUS_AGAIN || - result == G_IO_STATUS_ERROR) - return result; - } - - result = gnutls_record_send (chan->session, buf, count); - - /* I'm pretty sure this can't actually happen in response to a - * write, but... - */ - if (result == GNUTLS_E_REHANDSHAKE) { - chan->established = FALSE; - goto again; - } - - if (result == GNUTLS_E_INTERRUPTED || result == GNUTLS_E_AGAIN) { - if (chan->non_blocking || chan->eagain) - return G_IO_STATUS_AGAIN; - else - goto again; - } - - if (result < 0) { - g_set_error (err, G_IO_CHANNEL_ERROR, - G_IO_CHANNEL_ERROR_FAILED, - "Received corrupted data"); - return G_IO_STATUS_ERROR; - } else { - *bytes_written = result; - - return (result > 0) ? G_IO_STATUS_NORMAL : G_IO_STATUS_EOF; - } -} - -static GIOStatus -soup_gnutls_seek (GIOChannel *channel, - gint64 offset, - GSeekType type, - GError **err) -{ - SoupGNUTLSChannel *chan = (SoupGNUTLSChannel *) channel; - - return chan->real_sock->funcs->io_seek (chan->real_sock, offset, type, err); -} - -static GIOStatus -soup_gnutls_close (GIOChannel *channel, - GError **err) -{ - SoupGNUTLSChannel *chan = (SoupGNUTLSChannel *) channel; - - if (chan->established) { - int ret; - - do { - ret = gnutls_bye (chan->session, GNUTLS_SHUT_WR); - } while (ret == GNUTLS_E_INTERRUPTED); - } - - return chan->real_sock->funcs->io_close (chan->real_sock, err); -} - -static GSource * -soup_gnutls_create_watch (GIOChannel *channel, - GIOCondition condition) -{ - SoupGNUTLSChannel *chan = (SoupGNUTLSChannel *) channel; - - return chan->real_sock->funcs->io_create_watch (chan->real_sock, - condition); -} - -static void -soup_gnutls_free (GIOChannel *channel) -{ - SoupGNUTLSChannel *chan = (SoupGNUTLSChannel *) channel; - g_io_channel_unref (chan->real_sock); - gnutls_deinit (chan->session); - g_free (chan->hostname); - g_slice_free (SoupGNUTLSChannel, chan); -} - -static GIOStatus -soup_gnutls_set_flags (GIOChannel *channel, - GIOFlags flags, - GError **err) -{ - SoupGNUTLSChannel *chan = (SoupGNUTLSChannel *) channel; - - return chan->real_sock->funcs->io_set_flags (chan->real_sock, flags, err); -} - -static GIOFlags -soup_gnutls_get_flags (GIOChannel *channel) -{ - SoupGNUTLSChannel *chan = (SoupGNUTLSChannel *) channel; - - return chan->real_sock->funcs->io_get_flags (chan->real_sock); -} - -static const GIOFuncs soup_gnutls_channel_funcs = { - soup_gnutls_read, - soup_gnutls_write, - soup_gnutls_seek, - soup_gnutls_close, - soup_gnutls_create_watch, - soup_gnutls_free, - soup_gnutls_set_flags, - soup_gnutls_get_flags -}; - -static gnutls_dh_params dh_params = NULL; - -static gboolean -init_dh_params (void) -{ - static volatile gsize inited_dh_params = 0; - - if (g_once_init_enter (&inited_dh_params)) { - if (gnutls_dh_params_init (&dh_params) != 0 || - gnutls_dh_params_generate2 (dh_params, DH_BITS) != 0) { - if (dh_params) { - gnutls_dh_params_deinit (dh_params); - dh_params = NULL; - } - } - g_once_init_leave (&inited_dh_params, TRUE); - } - - return dh_params != NULL; -} - -static ssize_t -soup_gnutls_pull_func (gnutls_transport_ptr_t transport_data, - void *buf, size_t buflen) -{ - SoupGNUTLSChannel *chan = transport_data; - ssize_t nread; - - nread = recv (chan->sockfd, buf, buflen, 0); -#ifdef G_OS_WIN32 - { - int wsa_errno = WSAGetLastError (); - chan->eagain = (nread == SOCKET_ERROR && (wsa_errno == WSAEWOULDBLOCK || - wsa_errno == WSAETIMEDOUT)); - if (nread == SOCKET_ERROR) - gnutls_transport_set_errno (chan->session, - ((wsa_errno == WSAEWOULDBLOCK || - wsa_errno == WSAETIMEDOUT) ? EAGAIN : - (wsa_errno == WSAEINTR ? EINTR : - EIO))); - } -#else - chan->eagain = (nread == -1 && errno == EAGAIN); -#endif - return nread; -} - -static ssize_t -soup_gnutls_push_func (gnutls_transport_ptr_t transport_data, - const void *buf, size_t buflen) -{ - SoupGNUTLSChannel *chan = transport_data; - ssize_t nwrote; - - nwrote = send (chan->sockfd, buf, buflen, 0); -#ifdef G_OS_WIN32 - { - int wsa_errno = WSAGetLastError (); - chan->eagain = (nwrote == SOCKET_ERROR && wsa_errno == WSAEWOULDBLOCK); - if (nwrote == SOCKET_ERROR) - gnutls_transport_set_errno (chan->session, - (wsa_errno == WSAEWOULDBLOCK ? EAGAIN : - (wsa_errno == WSAEINTR ? EINTR : - EIO))); - } -#else - chan->eagain = (nwrote == -1 && errno == EAGAIN); -#endif - return nwrote; -} - -/** - * soup_ssl_wrap_iochannel: - * @sock: a #GIOChannel wrapping a TCP socket. - * @non_blocking: whether the underlying socket is blocking or not - * @type: whether this is a client or server socket - * @remote_host: the hostname of the remote machine - * @creds: a client or server credentials structure - * - * This attempts to wrap a new #GIOChannel around @sock that - * will SSL-encrypt/decrypt all traffic through it. - * - * Return value: an SSL-encrypting #GIOChannel, or %NULL on - * failure. - **/ -GIOChannel * -soup_ssl_wrap_iochannel (GIOChannel *sock, gboolean non_blocking, - SoupSSLType type, const char *remote_host, - SoupSSLCredentials *creds) -{ - SoupGNUTLSChannel *chan = NULL; - GIOChannel *gchan = NULL; - gnutls_session session = NULL; - int sockfd; - int ret; - - g_return_val_if_fail (sock != NULL, NULL); - g_return_val_if_fail (creds != NULL, NULL); - - sockfd = g_io_channel_unix_get_fd (sock); - if (!sockfd) { - g_warning ("Failed to get channel fd."); - goto THROW_CREATE_ERROR; - } - - ret = gnutls_init (&session, - (type == SOUP_SSL_TYPE_CLIENT) ? GNUTLS_CLIENT : GNUTLS_SERVER); - if (ret) - goto THROW_CREATE_ERROR; - - /* See http://bugzilla.gnome.org/show_bug.cgi?id=581342 */ - if (gnutls_priority_set_direct (session, "NORMAL:!VERS-TLS1.2:!VERS-TLS1.1:!VERS-TLS1.0", NULL) != 0) - goto THROW_CREATE_ERROR; - - if (gnutls_credentials_set (session, GNUTLS_CRD_CERTIFICATE, - creds->creds) != 0) - goto THROW_CREATE_ERROR; - - if (type == SOUP_SSL_TYPE_SERVER) - gnutls_dh_set_prime_bits (session, DH_BITS); - else { - // gnutls defaults to requiring at least 768-bit keys, - // but there are some lame servers out there... - gnutls_dh_set_prime_bits (session, 256); - } - - chan = g_slice_new0 (SoupGNUTLSChannel); - chan->real_sock = sock; - chan->sockfd = sockfd; - chan->session = session; - chan->creds = creds; - chan->hostname = g_strdup (remote_host); - chan->type = type; - chan->non_blocking = non_blocking; - g_io_channel_ref (sock); - - gnutls_transport_set_ptr (session, chan); - gnutls_transport_set_push_function (session, soup_gnutls_push_func); - gnutls_transport_set_pull_function (session, soup_gnutls_pull_func); - - gchan = (GIOChannel *) chan; - gchan->funcs = (GIOFuncs *)&soup_gnutls_channel_funcs; - g_io_channel_init (gchan); - gchan->is_readable = gchan->is_writeable = TRUE; - gchan->use_buffer = FALSE; - - return gchan; - - THROW_CREATE_ERROR: - if (session) - gnutls_deinit (session); - return NULL; -} - -#if defined(GCRY_THREAD_OPTION_PTHREAD_IMPL) && !defined(G_OS_WIN32) -GCRY_THREAD_OPTION_PTHREAD_IMPL; -#endif - -#ifdef G_OS_WIN32 - -static int -soup_gcry_win32_mutex_init (void **priv) -{ - int err = 0; - CRITICAL_SECTION *lock = (CRITICAL_SECTION*)malloc (sizeof (CRITICAL_SECTION)); - - if (!lock) - err = ENOMEM; - if (!err) { - InitializeCriticalSection (lock); - *priv = lock; - } - return err; -} - -static int -soup_gcry_win32_mutex_destroy (void **lock) -{ - DeleteCriticalSection ((CRITICAL_SECTION*)*lock); - free (*lock); - return 0; -} - -static int -soup_gcry_win32_mutex_lock (void **lock) -{ - EnterCriticalSection ((CRITICAL_SECTION*)*lock); - return 0; -} - -static int -soup_gcry_win32_mutex_unlock (void **lock) -{ - LeaveCriticalSection ((CRITICAL_SECTION*)*lock); - return 0; -} - - -static struct gcry_thread_cbs soup_gcry_threads_win32 = { \ - (GCRY_THREAD_OPTION_USER | (GCRY_THREAD_OPTION_VERSION << 8)), \ - NULL, soup_gcry_win32_mutex_init, soup_gcry_win32_mutex_destroy, \ - soup_gcry_win32_mutex_lock, soup_gcry_win32_mutex_unlock, \ - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; - -#endif - -static void -soup_gnutls_init (void) -{ - static volatile gsize inited_gnutls = 0; - - if (g_once_init_enter (&inited_gnutls)) { -#if defined(GCRY_THREAD_OPTION_PTHREAD_IMPL) && !defined(G_OS_WIN32) - gcry_control (GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread); -#elif defined(G_OS_WIN32) - gcry_control (GCRYCTL_SET_THREAD_CBS, &soup_gcry_threads_win32); -#endif - gnutls_global_init (); - g_once_init_leave (&inited_gnutls, TRUE); - } -} - -/** - * soup_ssl_get_client_credentials: - * @ca_file: path to a file containing X509-encoded Certificate - * Authority certificates. - * - * Creates an opaque client credentials object which can later be - * passed to soup_ssl_wrap_iochannel(). - * - * If @ca_file is non-%NULL, any certificate received from a server - * must be signed by one of the CAs in the file, or an error will - * be returned. - * - * Return value: the client credentials, which must be freed with - * soup_ssl_free_client_credentials(). - **/ -SoupSSLCredentials * -soup_ssl_get_client_credentials (const char *ca_file) -{ - SoupSSLCredentials *creds; - int status; - - soup_gnutls_init (); - - creds = g_slice_new0 (SoupSSLCredentials); - gnutls_certificate_allocate_credentials (&creds->creds); - - /* http://bugzilla.gnome.org/show_bug.cgi?id=589323 */ - gnutls_certificate_set_verify_flags (creds->creds, - GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT); - - if (ca_file) { - creds->have_ca_file = TRUE; - status = gnutls_certificate_set_x509_trust_file ( - creds->creds, ca_file, GNUTLS_X509_FMT_PEM); - if (status < 0) { - g_warning ("Failed to set SSL trust file (%s).", - ca_file); - /* Since we set have_ca_file though, this just - * means that no certs will validate, so we're - * ok securitywise if we just return these - * creds to the caller. - */ - } - } - - return creds; -} - -/** - * soup_ssl_free_client_credentials: - * @creds: a client credentials structure returned by - * soup_ssl_get_client_credentials(). - * - * Frees @creds. - **/ -void -soup_ssl_free_client_credentials (SoupSSLCredentials *creds) -{ - gnutls_certificate_free_credentials (creds->creds); - g_slice_free (SoupSSLCredentials, creds); -} - -/** - * soup_ssl_get_server_credentials: - * @cert_file: path to a file containing an X509-encoded server - * certificate - * @key_file: path to a file containing an X509-encoded key for - * @cert_file. - * - * Creates an opaque server credentials object which can later be - * passed to soup_ssl_wrap_iochannel(). - * - * Return value: the server credentials, which must be freed with - * soup_ssl_free_server_credentials(). - **/ -SoupSSLCredentials * -soup_ssl_get_server_credentials (const char *cert_file, const char *key_file) -{ - SoupSSLCredentials *creds; - - soup_gnutls_init (); - if (!init_dh_params ()) - return NULL; - - creds = g_slice_new0 (SoupSSLCredentials); - gnutls_certificate_allocate_credentials (&creds->creds); - - if (gnutls_certificate_set_x509_key_file (creds->creds, - cert_file, key_file, - GNUTLS_X509_FMT_PEM) != 0) { - g_warning ("Failed to set SSL certificate and key files " - "(%s, %s).", cert_file, key_file); - soup_ssl_free_server_credentials (creds); - return NULL; - } - - gnutls_certificate_set_dh_params (creds->creds, dh_params); - return creds; -} - -/** - * soup_ssl_free_server_credentials: - * @creds: a server credentials structure returned by - * soup_ssl_get_server_credentials(). - * - * Frees @creds. - **/ -void -soup_ssl_free_server_credentials (SoupSSLCredentials *creds) -{ - gnutls_certificate_free_credentials (creds->creds); - g_slice_free (SoupSSLCredentials, creds); -} - -#endif /* HAVE_SSL */ diff --git a/libsoup/soup-message-io.c b/libsoup/soup-message-io.c index 525ea71..e824b00 100644 --- a/libsoup/soup-message-io.c +++ b/libsoup/soup-message-io.c @@ -185,7 +185,7 @@ io_error (SoupSocket *sock, SoupMessage *msg, GError *error) SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg); SoupMessageIOData *io = priv->io_data; - if (error && error->domain == SOUP_SSL_ERROR) { + if (error && error->domain == G_TLS_ERROR) { soup_message_set_status_full (msg, SOUP_STATUS_SSL_FAILED, error->message); diff --git a/libsoup/soup-message-queue.h b/libsoup/soup-message-queue.h index 4f655b3..08cc6df 100644 --- a/libsoup/soup-message-queue.h +++ b/libsoup/soup-message-queue.h @@ -7,9 +7,6 @@ #ifndef SOUP_MESSAGE_QUEUE_H #define SOUP_MESSAGE_QUEUE_H 1 -#include -#include - #include "soup-connection.h" #include "soup-message.h" #include "soup-session.h" diff --git a/libsoup/soup-nossl.c b/libsoup/soup-nossl.c deleted file mode 100644 index 926854d..0000000 --- a/libsoup/soup-nossl.c +++ /dev/null @@ -1,91 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * soup-nossl.c - * - * Copyright (C) 2003, Ximian, Inc. - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include "soup-ssl.h" -#include "soup-misc.h" - -#ifndef HAVE_SSL - -const gboolean soup_ssl_supported = FALSE; - -GIOChannel * -soup_ssl_wrap_iochannel (GIOChannel *sock, gboolean non_blocking, - SoupSSLType type, const char *hostname, - SoupSSLCredentials *creds) -{ - return NULL; -} - -SoupSSLCredentials * -soup_ssl_get_client_credentials (const char *ca_file) -{ - /* We need to return something non-NULL, so SoupSocket will - * realize it's supposed to do SSL. If we returned NULL here, - * we'd eventually end up trying to speak plain http to an - * https server, probably resulting in a SOUP_STATUS_IO_ERROR - * or SOUP_STATUS_MALFORMED instead of SOUP_STATUS_SSL_FAILED. - */ - return g_malloc (1); -} - -void -soup_ssl_free_client_credentials (SoupSSLCredentials *client_creds) -{ - g_free (client_creds); -} - -SoupSSLCredentials * -soup_ssl_get_server_credentials (const char *cert_file, const char *key_file) -{ - /* See soup_ssl_get_client_credentials() */ - return g_malloc (1); -} - -void -soup_ssl_free_server_credentials (SoupSSLCredentials *server_creds) -{ - g_free (server_creds); -} - -#endif /* ! HAVE_SSL */ - -/** - * SOUP_SSL_ERROR: - * - * A #GError domain representing an SSL error. Used with #SoupSSLError. - **/ -/** - * soup_ssl_error_quark: - * - * The quark used as %SOUP_SSL_ERROR - * - * Return value: The quark used as %SOUP_SSL_ERROR - **/ -GQuark -soup_ssl_error_quark (void) -{ - static GQuark error; - if (!error) - error = g_quark_from_static_string ("soup_ssl_error_quark"); - return error; -} - -/** - * SoupSSLError: - * @SOUP_SSL_ERROR_HANDSHAKE_NEEDS_READ: Internal error. Never exposed - * outside of libsoup. - * @SOUP_SSL_ERROR_HANDSHAKE_NEEDS_WRITE: Internal error. Never exposed - * outside of libsoup. - * @SOUP_SSL_ERROR_CERTIFICATE: Indicates an error validating an SSL - * certificate - * - * SSL-related I/O errors. - **/ diff --git a/libsoup/soup-password-manager.h b/libsoup/soup-password-manager.h index 75f5cd8..775f84c 100644 --- a/libsoup/soup-password-manager.h +++ b/libsoup/soup-password-manager.h @@ -9,7 +9,6 @@ #ifdef LIBSOUP_I_HAVE_READ_BUG_594377_AND_KNOW_SOUP_PASSWORD_MANAGER_MIGHT_GO_AWAY #include -#include #define SOUP_TYPE_PASSWORD_MANAGER (soup_password_manager_get_type ()) #define SOUP_PASSWORD_MANAGER(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), SOUP_TYPE_PASSWORD_MANAGER, SoupPasswordManager)) diff --git a/libsoup/soup-portability.h b/libsoup/soup-portability.h index be00312..b36e7d7 100644 --- a/libsoup/soup-portability.h +++ b/libsoup/soup-portability.h @@ -6,7 +6,7 @@ #ifndef SOUP_PORTABILITY_H #define SOUP_PORTABILITY_H -#include +#include #ifdef G_OS_WIN32 diff --git a/libsoup/soup-proxy-resolver.h b/libsoup/soup-proxy-resolver.h index 991219f..dd78714 100644 --- a/libsoup/soup-proxy-resolver.h +++ b/libsoup/soup-proxy-resolver.h @@ -7,7 +7,6 @@ #define SOUP_PROXY_RESOLVER_H 1 #include -#include G_BEGIN_DECLS diff --git a/libsoup/soup-socket.c b/libsoup/soup-socket.c index 4e65891..c7d5716 100644 --- a/libsoup/soup-socket.c +++ b/libsoup/soup-socket.c @@ -22,9 +22,6 @@ #include "soup-misc.h" #include "soup-ssl.h" -#include -#include - /** * SECTION:soup-socket * @short_description: A network socket @@ -65,14 +62,14 @@ enum { }; typedef struct { - int sockfd; SoupAddress *local_addr, *remote_addr; - GIOChannel *iochannel; - GSocketConnection *conn; + GIOStream *conn; + GSocket *gsock; + GPollableInputStream *istream; + GPollableOutputStream *ostream; guint non_blocking:1; guint is_server:1; - guint timed_out:1; guint ssl_strict:1; guint trusted_certificate:1; guint clean_dispose:1; @@ -81,7 +78,6 @@ typedef struct { GMainContext *async_context; GSource *watch_src; GSource *read_src, *write_src; - GSource *read_timeout, *write_timeout; GByteArray *read_buf; GMutex *iolock, *addrlock; @@ -96,39 +92,30 @@ static void set_property (GObject *object, guint prop_id, static void get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec); -#ifdef G_OS_WIN32 -#define SOUP_IS_SOCKET_ERROR(status) ((status) == SOCKET_ERROR) -#define SOUP_IS_INVALID_SOCKET(socket) ((socket) == INVALID_SOCKET) -#define SHUT_RDWR SD_BOTH -#else -#define SOUP_IS_SOCKET_ERROR(status) ((status) == -1) -#define SOUP_IS_INVALID_SOCKET(socket) ((socket) < 0) -#endif - static void soup_socket_init (SoupSocket *sock) { SoupSocketPrivate *priv = SOUP_SOCKET_GET_PRIVATE (sock); - priv->sockfd = -1; priv->non_blocking = TRUE; priv->addrlock = g_mutex_new (); priv->iolock = g_mutex_new (); - priv->timeout = 0; } static void disconnect_internal (SoupSocketPrivate *priv) { - if (priv->iochannel) { - g_io_channel_unref (priv->iochannel); - priv->iochannel = NULL; + if (priv->gsock) { + g_socket_close (priv->gsock, NULL); + g_object_unref (priv->gsock); + priv->gsock = NULL; } if (priv->conn) { g_object_unref (priv->conn); priv->conn = NULL; + priv->istream = NULL; + priv->ostream = NULL; } - priv->sockfd = -1; if (priv->read_src) { g_source_destroy (priv->read_src); @@ -138,14 +125,6 @@ disconnect_internal (SoupSocketPrivate *priv) g_source_destroy (priv->write_src); priv->write_src = NULL; } - if (priv->read_timeout) { - g_source_destroy (priv->read_timeout); - priv->read_timeout = NULL; - } - if (priv->write_timeout) { - g_source_destroy (priv->write_timeout); - priv->write_timeout = NULL; - } } static void @@ -158,7 +137,7 @@ finalize (GObject *object) g_warning ("Disposing socket %p during connect", object); g_object_unref (priv->connect_cancel); } - if (priv->iochannel) { + if (priv->conn) { if (priv->clean_dispose) g_warning ("Disposing socket %p while still connected", object); disconnect_internal (priv); @@ -424,93 +403,19 @@ soup_socket_class_init (SoupSocketClass *socket_class) static void -set_nonblocking (SoupSocketPrivate *priv) +finish_socket_setup (SoupSocketPrivate *priv) { -#ifndef G_OS_WIN32 - int flags; -#else - u_long val; -#endif - - if (priv->sockfd == -1) + if (!priv->gsock) return; -#ifndef G_OS_WIN32 - flags = fcntl (priv->sockfd, F_GETFL, 0); - if (flags != -1) { - if (priv->non_blocking) - flags |= O_NONBLOCK; - else - flags &= ~O_NONBLOCK; - fcntl (priv->sockfd, F_SETFL, flags); - } -#else - val = priv->non_blocking ? 1 : 0; - ioctlsocket (priv->sockfd, FIONBIO, &val); -#endif -} + if (!priv->conn) + priv->conn = (GIOStream *)g_socket_connection_factory_create_connection (priv->gsock); + if (!priv->istream) + priv->istream = G_POLLABLE_INPUT_STREAM (g_io_stream_get_input_stream (priv->conn)); + if (!priv->ostream) + priv->ostream = G_POLLABLE_OUTPUT_STREAM (g_io_stream_get_output_stream (priv->conn)); -static void -set_fdflags (SoupSocketPrivate *priv) -{ - int opt; -#ifndef G_OS_WIN32 - struct timeval timeout; - int flags; -#endif - - if (priv->sockfd == -1) - return; - - set_nonblocking (priv); - -#ifndef G_OS_WIN32 - flags = fcntl (priv->sockfd, F_GETFD, 0); - if (flags != -1) { - flags |= FD_CLOEXEC; - fcntl (priv->sockfd, F_SETFD, flags); - } -#endif - - opt = 1; - setsockopt (priv->sockfd, IPPROTO_TCP, - TCP_NODELAY, (void *) &opt, sizeof (opt)); - setsockopt (priv->sockfd, SOL_SOCKET, - SO_REUSEADDR, (void *) &opt, sizeof (opt)); - -#ifndef G_OS_WIN32 - timeout.tv_sec = priv->timeout; - timeout.tv_usec = 0; - setsockopt (priv->sockfd, SOL_SOCKET, - SO_RCVTIMEO, (void *) &timeout, sizeof (timeout)); - - timeout.tv_sec = priv->timeout; - timeout.tv_usec = 0; - setsockopt (priv->sockfd, SOL_SOCKET, - SO_SNDTIMEO, (void *) &timeout, sizeof (timeout)); -#else - if (priv->timeout < G_MAXINT / 1000) - opt = priv->timeout * 1000; - else - opt = 0; - - setsockopt (priv->sockfd, SOL_SOCKET, - SO_RCVTIMEO, (void *) &opt, sizeof (opt)); - - setsockopt (priv->sockfd, SOL_SOCKET, - SO_SNDTIMEO, (void *) &opt, sizeof (opt)); -#endif - -#ifndef G_OS_WIN32 - priv->iochannel = - g_io_channel_unix_new (priv->sockfd); -#else - priv->iochannel = - g_io_channel_win32_new_socket (priv->sockfd); -#endif - g_io_channel_set_close_on_unref (priv->iochannel, priv->conn == NULL); - g_io_channel_set_encoding (priv->iochannel, NULL, NULL); - g_io_channel_set_buffered (priv->iochannel, FALSE); + g_socket_set_timeout (priv->gsock, priv->timeout); } static void @@ -528,7 +433,6 @@ set_property (GObject *object, guint prop_id, break; case PROP_NON_BLOCKING: priv->non_blocking = g_value_get_boolean (value); - set_nonblocking (priv); break; case PROP_SSL_CREDENTIALS: priv->ssl_creds = g_value_get_pointer (value); @@ -546,6 +450,8 @@ set_property (GObject *object, guint prop_id, break; case PROP_TIMEOUT: priv->timeout = g_value_get_uint (value); + if (priv->conn) + g_socket_set_timeout (priv->gsock, priv->timeout); break; case PROP_CLEAN_DISPOSE: priv->clean_dispose = g_value_get_boolean (value); @@ -624,7 +530,6 @@ static guint socket_connected (SoupSocket *sock, GSocketConnection *conn, GError *error) { SoupSocketPrivate *priv = SOUP_SOCKET_GET_PRIVATE (sock); - GSocket *gsock; g_object_unref (priv->connect_cancel); priv->connect_cancel = NULL; @@ -639,14 +544,9 @@ socket_connected (SoupSocket *sock, GSocketConnection *conn, GError *error) } } - /* We keep the GSocketConnection around because its GSocket - * will close the fd when it's destroyed. - */ - priv->conn = conn; - - gsock = g_socket_connection_get_socket (conn); - priv->sockfd = g_socket_get_fd (gsock); - set_fdflags (priv); + priv->conn = (GIOStream *)conn; + priv->gsock = g_object_ref (g_socket_connection_get_socket (conn)); + finish_socket_setup (priv); return SOUP_STATUS_OK; } @@ -725,14 +625,8 @@ soup_socket_connect_async (SoupSocket *sock, GCancellable *cancellable, g_main_context_push_thread_default (priv->async_context); client = g_socket_client_new (); - if (priv->timeout) { - /* FIXME: temporary workaround for not-new-enough glib */ - if (g_object_class_find_property (G_OBJECT_GET_CLASS (client), "timeout")) { - g_object_set (G_OBJECT (client), - "timeout", priv->timeout, - NULL); - } - } + if (priv->timeout) + g_socket_client_set_timeout (client, priv->timeout); g_socket_client_connect_async (client, G_SOCKET_CONNECTABLE (priv->remote_addr), priv->connect_cancel, @@ -764,7 +658,7 @@ soup_socket_connect_sync (SoupSocket *sock, GCancellable *cancellable) g_return_val_if_fail (SOUP_IS_SOCKET (sock), SOUP_STATUS_MALFORMED); priv = SOUP_SOCKET_GET_PRIVATE (sock); g_return_val_if_fail (!priv->is_server, SOUP_STATUS_MALFORMED); - g_return_val_if_fail (priv->sockfd == -1, SOUP_STATUS_MALFORMED); + g_return_val_if_fail (priv->gsock == NULL, SOUP_STATUS_MALFORMED); g_return_val_if_fail (priv->remote_addr != NULL, SOUP_STATUS_MALFORMED); if (cancellable) @@ -774,14 +668,8 @@ soup_socket_connect_sync (SoupSocket *sock, GCancellable *cancellable) priv->connect_cancel = cancellable; client = g_socket_client_new (); - if (priv->timeout) { - /* FIXME: temporary workaround for not-new-enough glib */ - if (g_object_class_find_property (G_OBJECT_GET_CLASS (client), "timeout")) { - g_object_set (G_OBJECT (client), - "timeout", priv->timeout, - NULL); - } - } + if (priv->timeout) + g_socket_client_set_timeout (client, priv->timeout); conn = g_socket_client_connect (client, G_SOCKET_CONNECTABLE (priv->remote_addr), priv->connect_cancel, &error); @@ -795,41 +683,51 @@ soup_socket_get_fd (SoupSocket *sock) { g_return_val_if_fail (SOUP_IS_SOCKET (sock), -1); - return SOUP_SOCKET_GET_PRIVATE (sock)->sockfd; + return g_socket_get_fd (SOUP_SOCKET_GET_PRIVATE (sock)->gsock); +} + +static GSource * +soup_socket_create_watch (SoupSocketPrivate *priv, GIOCondition cond, + GPollableSourceFunc callback, gpointer user_data, + GCancellable *cancellable) +{ + GSource *watch; + + if (cond == G_IO_IN) + watch = g_pollable_input_stream_create_source (priv->istream, cancellable); + else + watch = g_pollable_output_stream_create_source (priv->ostream, cancellable); + g_source_set_callback (watch, (GSourceFunc)callback, user_data, NULL); + g_source_attach (watch, priv->async_context); + g_source_unref (watch); + + return watch; } static gboolean -listen_watch (GIOChannel* iochannel, GIOCondition condition, gpointer data) +listen_watch (GObject *pollable, gpointer data) { SoupSocket *sock = data, *new; SoupSocketPrivate *priv = SOUP_SOCKET_GET_PRIVATE (sock), *new_priv; - struct sockaddr_storage sa; - int sa_len, sockfd; + GSocket *new_gsock; - if (condition & (G_IO_HUP | G_IO_ERR)) { - priv->watch_src = NULL; + new_gsock = g_socket_accept (priv->gsock, NULL, NULL); + if (!new_gsock) return FALSE; - } - - sa_len = sizeof (sa); - sockfd = accept (priv->sockfd, (struct sockaddr *)&sa, (void *)&sa_len); - if (SOUP_IS_INVALID_SOCKET (sockfd)) - return TRUE; new = g_object_new (SOUP_TYPE_SOCKET, NULL); new_priv = SOUP_SOCKET_GET_PRIVATE (new); - new_priv->sockfd = sockfd; + new_priv->gsock = new_gsock; if (priv->async_context) new_priv->async_context = g_main_context_ref (priv->async_context); new_priv->non_blocking = priv->non_blocking; new_priv->is_server = TRUE; - new_priv->ssl_creds = priv->ssl_creds; - set_fdflags (new_priv); - - new_priv->remote_addr = soup_address_new_from_sockaddr ((struct sockaddr *)&sa, sa_len); + if (priv->ssl_creds) + new_priv->ssl_creds = priv->ssl_creds; + finish_socket_setup (new_priv); if (new_priv->ssl_creds) { - if (!soup_socket_start_ssl (new, NULL)) { + if (!soup_socket_start_proxy_ssl (new, NULL, NULL)) { g_object_unref (new); return TRUE; } @@ -856,13 +754,11 @@ soup_socket_listen (SoupSocket *sock) { SoupSocketPrivate *priv; - struct sockaddr_storage sa; - int sa_len; GSocketAddress *addr; g_return_val_if_fail (SOUP_IS_SOCKET (sock), FALSE); priv = SOUP_SOCKET_GET_PRIVATE (sock); - g_return_val_if_fail (priv->sockfd == -1, FALSE); + g_return_val_if_fail (priv->gsock == NULL, FALSE); g_return_val_if_fail (priv->local_addr != NULL, FALSE); priv->is_server = TRUE; @@ -876,39 +772,54 @@ soup_socket_listen (SoupSocket *sock) addr = soup_address_get_gsockaddr (priv->local_addr); g_return_val_if_fail (addr != NULL, FALSE); - sa_len = g_socket_address_get_native_size (addr); - g_socket_address_to_native (addr, &sa, sizeof (sa), NULL); - g_object_unref (addr); - - priv->sockfd = socket (sa.ss_family, SOCK_STREAM, 0); - if (SOUP_IS_INVALID_SOCKET (priv->sockfd)) + priv->gsock = g_socket_new (g_socket_address_get_family (addr), + G_SOCKET_TYPE_STREAM, + G_SOCKET_PROTOCOL_DEFAULT, + NULL); + if (!priv->gsock) goto cant_listen; - set_fdflags (priv); + finish_socket_setup (priv); /* Bind */ - if (bind (priv->sockfd, (struct sockaddr *)&sa, sa_len) != 0) + if (!g_socket_bind (priv->gsock, addr, TRUE, NULL)) goto cant_listen; /* Force local_addr to be re-resolved now */ g_object_unref (priv->local_addr); priv->local_addr = NULL; /* Listen */ - if (listen (priv->sockfd, 10) != 0) + if (!g_socket_listen (priv->gsock, NULL)) goto cant_listen; - priv->watch_src = soup_add_io_watch (priv->async_context, - priv->iochannel, - G_IO_IN | G_IO_ERR | G_IO_HUP, - listen_watch, sock); + priv->watch_src = soup_socket_create_watch (priv, G_IO_IN, + listen_watch, sock, + NULL); return TRUE; cant_listen: - if (priv->iochannel) + if (priv->conn) disconnect_internal (priv); return FALSE; } +static gboolean +soup_socket_accept_certificate (GTlsConnection *conn, GTlsCertificate *cert, + GTlsCertificateFlags errors, gpointer sock) +{ + SoupSocketPrivate *priv = SOUP_SOCKET_GET_PRIVATE (sock); + + if (soup_ssl_credentials_verify_certificate (priv->ssl_creds, + cert, errors)) + return TRUE; + + if (!priv->ssl_strict) { + priv->trusted_certificate = FALSE; + return TRUE; + } + return FALSE; +} + /** * soup_socket_start_ssl: * @sock: the socket @@ -942,27 +853,57 @@ soup_socket_start_proxy_ssl (SoupSocket *sock, const char *ssl_host, GCancellable *cancellable) { SoupSocketPrivate *priv = SOUP_SOCKET_GET_PRIVATE (sock); - GIOChannel *ssl_chan; - GIOChannel *real_chan; - - real_chan = priv->iochannel; - ssl_chan = soup_ssl_wrap_iochannel ( - real_chan, priv->non_blocking, priv->is_server ? - SOUP_SSL_TYPE_SERVER : SOUP_SSL_TYPE_CLIENT, - ssl_host, priv->ssl_creds); + GTlsBackend *backend = g_tls_backend_get_default (); - if (!ssl_chan) + if (G_IS_TLS_CONNECTION (priv->conn)) + return TRUE; + if (!priv->ssl_creds) return FALSE; - /* This is optimistic, we will set this to false if we get a - * cert error from one of the I/O calls - */ - if (priv->ssl_creds) + if (!priv->is_server) { + GTlsClientConnection *conn; + GSocketConnectable *identity; + + identity = g_network_address_new (ssl_host, 0); + conn = g_initable_new (g_tls_backend_get_client_connection_type (backend), + NULL, NULL, + "base-io-stream", priv->conn, + "server-identity", identity, + "use-system-certdb", FALSE, + "require-close-notify", FALSE, + "use-ssl3", TRUE, + NULL); + g_object_unref (identity); + + if (!conn) + return FALSE; + + g_object_unref (priv->conn); + priv->conn = G_IO_STREAM (conn); + priv->trusted_certificate = TRUE; + g_signal_connect (conn, "accept-certificate", + G_CALLBACK (soup_socket_accept_certificate), + sock); + } else { + GTlsServerConnection *conn; + + conn = g_initable_new (g_tls_backend_get_server_connection_type (backend), + NULL, NULL, + "base-io-stream", priv->conn, + "certificate", soup_ssl_credentials_get_certificate (priv->ssl_creds), + "use-system-certdb", FALSE, + "require-close-notify", FALSE, + NULL); + if (!conn) + return FALSE; - priv->iochannel = ssl_chan; - g_io_channel_unref (real_chan); + g_object_unref (priv->conn); + priv->conn = G_IO_STREAM (conn); + } + priv->istream = G_POLLABLE_INPUT_STREAM (g_io_stream_get_input_stream (priv->conn)); + priv->ostream = G_POLLABLE_OUTPUT_STREAM (g_io_stream_get_output_stream (priv->conn)); return TRUE; } @@ -1004,27 +945,19 @@ soup_socket_disconnect (SoupSocket *sock) g_cancellable_cancel (priv->connect_cancel); return; } else if (g_mutex_trylock (priv->iolock)) { - if (priv->iochannel) + if (priv->conn) disconnect_internal (priv); else already_disconnected = TRUE; g_mutex_unlock (priv->iolock); } else { - int sockfd; - /* Another thread is currently doing IO, so - * we can't close the iochannel. So just shutdown + * we can't close the socket. So just shutdown * the file descriptor to force the I/O to fail. - * (It will actually be closed when the socket is - * destroyed.) + * (It will actually be closed when the socket + * is destroyed.) */ - sockfd = priv->sockfd; - priv->sockfd = -1; - - if (sockfd == -1) - already_disconnected = TRUE; - else - shutdown (sockfd, SHUT_RDWR); + g_socket_shutdown (priv->gsock, TRUE, TRUE, NULL); } if (already_disconnected) @@ -1062,7 +995,7 @@ soup_socket_is_connected (SoupSocket *sock) g_return_val_if_fail (SOUP_IS_SOCKET (sock), FALSE); priv = SOUP_SOCKET_GET_PRIVATE (sock); - return priv->iochannel != NULL; + return priv->conn != NULL; } /** @@ -1083,12 +1016,15 @@ soup_socket_get_local_address (SoupSocket *sock) g_mutex_lock (priv->addrlock); if (!priv->local_addr) { - struct sockaddr_storage bound_sa; - int sa_len; - - sa_len = sizeof (bound_sa); - getsockname (priv->sockfd, (struct sockaddr *)&bound_sa, (void *)&sa_len); - priv->local_addr = soup_address_new_from_sockaddr ((struct sockaddr *)&bound_sa, sa_len); + GSocketAddress *addr; + struct sockaddr_storage sa; + gssize sa_len; + + addr = g_socket_get_local_address (priv->gsock, NULL); + sa_len = g_socket_address_get_native_size (addr); + g_socket_address_to_native (addr, &sa, sa_len, NULL); + priv->local_addr = soup_address_new_from_sockaddr ((struct sockaddr *)&sa, sa_len); + g_object_unref (addr); } g_mutex_unlock (priv->addrlock); @@ -1113,12 +1049,15 @@ soup_socket_get_remote_address (SoupSocket *sock) g_mutex_lock (priv->addrlock); if (!priv->remote_addr) { - struct sockaddr_storage bound_sa; - int sa_len; - - sa_len = sizeof (bound_sa); - getpeername (priv->sockfd, (struct sockaddr *)&bound_sa, (void *)&sa_len); - priv->remote_addr = soup_address_new_from_sockaddr ((struct sockaddr *)&bound_sa, sa_len); + GSocketAddress *addr; + struct sockaddr_storage sa; + gssize sa_len; + + addr = g_socket_get_remote_address (priv->gsock, NULL); + sa_len = g_socket_address_get_native_size (addr); + g_socket_address_to_native (addr, &sa, sa_len, NULL); + priv->local_addr = soup_address_new_from_sockaddr ((struct sockaddr *)&sa, sa_len); + g_object_unref (addr); } g_mutex_unlock (priv->addrlock); @@ -1127,128 +1066,63 @@ soup_socket_get_remote_address (SoupSocket *sock) static gboolean -socket_timeout (gpointer sock) -{ - SoupSocketPrivate *priv = SOUP_SOCKET_GET_PRIVATE (sock); - gboolean readable = FALSE, writable = FALSE; - - priv->timed_out = TRUE; - if (priv->read_timeout) { - priv->read_timeout = NULL; - readable = TRUE; - } - if (priv->write_timeout) { - priv->write_timeout = NULL; - writable = TRUE; - } - - if (readable) - g_signal_emit (sock, signals[READABLE], 0); - if (writable) - g_signal_emit (sock, signals[WRITABLE], 0); - - return FALSE; -} - -static gboolean -socket_read_watch (GIOChannel *chan, GIOCondition cond, gpointer user_data) +socket_read_watch (GObject *pollable, gpointer user_data) { SoupSocket *sock = user_data; SoupSocketPrivate *priv = SOUP_SOCKET_GET_PRIVATE (sock); priv->read_src = NULL; - if (priv->read_timeout) { - g_source_destroy (priv->read_timeout); - priv->read_timeout = NULL; - } - - if (cond & (G_IO_ERR | G_IO_HUP)) - soup_socket_disconnect (sock); - else - g_signal_emit (sock, signals[READABLE], 0); - + g_signal_emit (sock, signals[READABLE], 0); return FALSE; } static SoupSocketIOStatus read_from_network (SoupSocket *sock, gpointer buffer, gsize len, - gsize *nread, GError **error) + gsize *nread, GCancellable *cancellable, GError **error) { SoupSocketPrivate *priv = SOUP_SOCKET_GET_PRIVATE (sock); - GIOStatus status; - GIOCondition cond = G_IO_IN; GError *my_err = NULL; + gssize my_nread; *nread = 0; - if (!priv->iochannel) + if (!priv->conn) return SOUP_SOCKET_EOF; - if (priv->timed_out) { - g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_TIMED_OUT, - "Timed out"); - return SOUP_SOCKET_ERROR; - } - -again: - status = g_io_channel_read_chars (priv->iochannel, - buffer, len, nread, &my_err); - if (my_err) { - if (g_error_matches (my_err, SOUP_SSL_ERROR, - SOUP_SSL_ERROR_CERTIFICATE) && - !priv->ssl_strict) { - priv->trusted_certificate = FALSE; - g_clear_error (&my_err); - goto again; - } - - if (g_error_matches (my_err, SOUP_SSL_ERROR, - SOUP_SSL_ERROR_HANDSHAKE_NEEDS_WRITE)) - cond = G_IO_OUT; - g_propagate_error (error, my_err); + if (!priv->non_blocking) { + my_nread = g_input_stream_read (G_INPUT_STREAM (priv->istream), + buffer, len, + cancellable, &my_err); + } else { + my_nread = g_pollable_input_stream_read_nonblocking ( + priv->istream, buffer, len, + cancellable, &my_err); } - switch (status) { - case G_IO_STATUS_NORMAL: - case G_IO_STATUS_AGAIN: - if (*nread > 0) { - g_clear_error (error); - return SOUP_SOCKET_OK; - } - - /* If the socket is sync and we get EAGAIN, then it is - * a socket timeout and should be treated as an error - * condition. - */ - if (!priv->non_blocking) { - g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_TIMED_OUT, - "Timed out"); - return SOUP_SOCKET_ERROR; - } - + if (my_nread > 0) { + g_clear_error (&my_err); + *nread = my_nread; + return SOUP_SOCKET_OK; + } else if (my_nread == 0) { + g_clear_error (&my_err); + *nread = my_nread; + return SOUP_SOCKET_EOF; + } else if (g_error_matches (my_err, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK)) { + g_clear_error (&my_err); if (!priv->read_src) { priv->read_src = - soup_add_io_watch (priv->async_context, - priv->iochannel, - cond | G_IO_HUP | G_IO_ERR, - socket_read_watch, sock); - if (priv->timeout) { - priv->read_timeout = - soup_add_timeout (priv->async_context, - priv->timeout * 1000, - socket_timeout, sock); - } + soup_socket_create_watch (priv, G_IO_IN, + socket_read_watch, sock, + cancellable); } - g_clear_error (error); return SOUP_SOCKET_WOULD_BLOCK; - - case G_IO_STATUS_EOF: - g_clear_error (error); - return SOUP_SOCKET_EOF; - - default: - return SOUP_SOCKET_ERROR; + } else if (g_error_matches (my_err, G_TLS_ERROR, G_TLS_ERROR_HANDSHAKE)) { + my_err->domain = SOUP_SSL_ERROR; + my_err->code = SOUP_SSL_ERROR_CERTIFICATE; } + + g_propagate_error (error, my_err); + return SOUP_SOCKET_ERROR; } static SoupSocketIOStatus @@ -1325,7 +1199,7 @@ soup_socket_read (SoupSocket *sock, gpointer buffer, gsize len, if (priv->read_buf) status = read_from_buf (sock, buffer, len, nread); else - status = read_from_network (sock, buffer, len, nread, error); + status = read_from_network (sock, buffer, len, nread, cancellable, error); g_mutex_unlock (priv->iolock); return status; @@ -1390,7 +1264,7 @@ soup_socket_read_until (SoupSocket *sock, gpointer buffer, gsize len, g_byte_array_set_size (read_buf, len); status = read_from_network (sock, read_buf->data + prev_len, - len - prev_len, nread, error); + len - prev_len, nread, cancellable, error); read_buf->len = prev_len + *nread; if (status != SOUP_SOCKET_OK) { @@ -1421,22 +1295,13 @@ soup_socket_read_until (SoupSocket *sock, gpointer buffer, gsize len, } static gboolean -socket_write_watch (GIOChannel *chan, GIOCondition cond, gpointer user_data) +socket_write_watch (GObject *pollable, gpointer user_data) { SoupSocket *sock = user_data; SoupSocketPrivate *priv = SOUP_SOCKET_GET_PRIVATE (sock); priv->write_src = NULL; - if (priv->write_timeout) { - g_source_destroy (priv->write_timeout); - priv->write_timeout = NULL; - } - - if (cond & (G_IO_ERR | G_IO_HUP)) - soup_socket_disconnect (sock); - else - g_signal_emit (sock, signals[WRITABLE], 0); - + g_signal_emit (sock, signals[WRITABLE], 0); return FALSE; } @@ -1472,9 +1337,8 @@ soup_socket_write (SoupSocket *sock, gconstpointer buffer, GCancellable *cancellable, GError **error) { SoupSocketPrivate *priv; - GIOStatus status; - GIOCondition cond = G_IO_OUT; GError *my_err = NULL; + gssize my_nwrote; g_return_val_if_fail (SOUP_IS_SOCKET (sock), SOUP_SOCKET_ERROR); g_return_val_if_fail (nwrote != NULL, SOUP_SOCKET_ERROR); @@ -1483,72 +1347,46 @@ soup_socket_write (SoupSocket *sock, gconstpointer buffer, g_mutex_lock (priv->iolock); - if (!priv->iochannel) { + if (!priv->conn) { g_mutex_unlock (priv->iolock); return SOUP_SOCKET_EOF; } - if (priv->timed_out) { - g_mutex_unlock (priv->iolock); - g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_TIMED_OUT, - "Timed out"); - return SOUP_SOCKET_ERROR; - } if (priv->write_src) { g_mutex_unlock (priv->iolock); return SOUP_SOCKET_WOULD_BLOCK; } -again: - status = g_io_channel_write_chars (priv->iochannel, - buffer, len, nwrote, &my_err); - if (my_err) { - if (g_error_matches (my_err, SOUP_SSL_ERROR, - SOUP_SSL_ERROR_CERTIFICATE) && - !priv->ssl_strict) { - priv->trusted_certificate = FALSE; - g_clear_error (&my_err); - goto again; - } - - if (g_error_matches (my_err, SOUP_SSL_ERROR, - SOUP_SSL_ERROR_HANDSHAKE_NEEDS_READ)) - cond = G_IO_IN; - g_propagate_error (error, my_err); - } - - /* If the socket is sync and we get EAGAIN, then it is a - * socket timeout and should be treated as an error condition. - */ - if (!priv->non_blocking && status == G_IO_STATUS_AGAIN) { - g_mutex_unlock (priv->iolock); - g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_TIMED_OUT, - "Timed out"); - return SOUP_SOCKET_ERROR; + if (!priv->non_blocking) { + my_nwrote = g_output_stream_write (G_OUTPUT_STREAM (priv->ostream), + buffer, len, + cancellable, &my_err); + } else { + my_nwrote = g_pollable_output_stream_write_nonblocking ( + priv->ostream, buffer, len, + cancellable, &my_err); } - if (status != G_IO_STATUS_NORMAL && status != G_IO_STATUS_AGAIN) { + if (my_nwrote > 0) { g_mutex_unlock (priv->iolock); - return SOUP_SOCKET_ERROR; + g_clear_error (&my_err); + *nwrote = my_nwrote; + return SOUP_SOCKET_OK; } - g_clear_error (error); - - if (*nwrote) { + if (g_error_matches (my_err, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK)) { g_mutex_unlock (priv->iolock); - return SOUP_SOCKET_OK; - } - priv->write_src = - soup_add_io_watch (priv->async_context, - priv->iochannel, - cond | G_IO_HUP | G_IO_ERR, - socket_write_watch, sock); - if (priv->timeout) { - priv->write_timeout = soup_add_timeout (priv->async_context, - priv->timeout * 1000, - socket_timeout, sock); + priv->write_src = + soup_socket_create_watch (priv, + G_IO_OUT, + socket_write_watch, sock, cancellable); + return SOUP_SOCKET_WOULD_BLOCK; + } else if (g_error_matches (my_err, G_TLS_ERROR, G_TLS_ERROR_HANDSHAKE)) { + my_err->domain = SOUP_SSL_ERROR; + my_err->code = SOUP_SSL_ERROR_CERTIFICATE; } g_mutex_unlock (priv->iolock); - return SOUP_SOCKET_WOULD_BLOCK; + g_propagate_error (error, my_err); + return SOUP_SOCKET_ERROR; } diff --git a/libsoup/soup-socket.h b/libsoup/soup-socket.h index 2e039d9..058e930 100644 --- a/libsoup/soup-socket.h +++ b/libsoup/soup-socket.h @@ -7,7 +7,6 @@ #define SOUP_SOCKET_H 1 #include -#include G_BEGIN_DECLS diff --git a/libsoup/soup-ssl.c b/libsoup/soup-ssl.c new file mode 100644 index 0000000..71c4dc1 --- /dev/null +++ b/libsoup/soup-ssl.c @@ -0,0 +1,143 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * soup-ssl.c: temporary ssl integration + * + * Copyright (C) 2010 Red Hat, Inc. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include "soup-ssl.h" +#include "soup-misc.h" + +const gboolean soup_ssl_supported = TRUE; + +struct SoupSSLCredentials { + GList *ca_list; + GTlsCertificateFlags validation_flags; + GTlsCertificate *certificate; +}; + +SoupSSLCredentials * +soup_ssl_get_client_credentials (const char *ca_file) +{ + SoupSSLCredentials *creds; + + creds = g_slice_new0 (SoupSSLCredentials); + + if (ca_file) { + GError *error = NULL; + + creds->ca_list = g_tls_certificate_list_new_from_file (ca_file, &error); + if (error) { + g_warning ("Could not set SSL credentials from '%s': %s", + ca_file, error->message); + g_error_free (error); + } + creds->validation_flags = G_TLS_CERTIFICATE_VALIDATE_ALL; + } + + return creds; +} + +gboolean +soup_ssl_credentials_verify_certificate (SoupSSLCredentials *creds, + GTlsCertificate *cert, + GTlsCertificateFlags errors) +{ + errors = errors & creds->validation_flags; + + if (errors & G_TLS_CERTIFICATE_UNKNOWN_CA) { + GList *ca; + + for (ca = creds->ca_list; ca; ca = ca->next) { + if ((g_tls_certificate_verify (cert, NULL, ca->data) & G_TLS_CERTIFICATE_UNKNOWN_CA) == 0) { + errors &= ~G_TLS_CERTIFICATE_UNKNOWN_CA; + break; + } + } + } + + return errors == 0; +} + +void +soup_ssl_free_client_credentials (SoupSSLCredentials *client_creds) +{ + GList *c; + + for (c = client_creds->ca_list; c; c = c->next) + g_object_unref (c->data); + g_list_free (client_creds->ca_list); + g_slice_free (SoupSSLCredentials, client_creds); +} + +SoupSSLCredentials * +soup_ssl_get_server_credentials (const char *cert_file, const char *key_file) +{ + SoupSSLCredentials *creds; + GError *error = NULL; + + creds = g_slice_new0 (SoupSSLCredentials); + + creds->certificate = g_tls_certificate_new_from_files (cert_file, key_file, &error); + if (!creds->certificate) { + g_warning ("Could not read SSL certificate from '%s': %s", + cert_file, error->message); + g_error_free (error); + g_slice_free (SoupSSLCredentials, creds); + return NULL; + } + + return creds; +} + +GTlsCertificate * +soup_ssl_credentials_get_certificate (SoupSSLCredentials *creds) +{ + return creds->certificate; +} + +void +soup_ssl_free_server_credentials (SoupSSLCredentials *server_creds) +{ + g_object_unref (server_creds->certificate); + g_slice_free (SoupSSLCredentials, server_creds); +} + +/** + * SOUP_SSL_ERROR: + * + * A #GError domain representing an SSL error. Used with #SoupSSLError. + **/ +/** + * soup_ssl_error_quark: + * + * The quark used as %SOUP_SSL_ERROR + * + * Return value: The quark used as %SOUP_SSL_ERROR + **/ +GQuark +soup_ssl_error_quark (void) +{ + static GQuark error; + if (!error) + error = g_quark_from_static_string ("soup_ssl_error_quark"); + return error; +} + +/** + * SoupSSLError: + * @SOUP_SSL_ERROR_HANDSHAKE_NEEDS_READ: Internal error. Never exposed + * outside of libsoup. + * @SOUP_SSL_ERROR_HANDSHAKE_NEEDS_WRITE: Internal error. Never exposed + * outside of libsoup. + * @SOUP_SSL_ERROR_CERTIFICATE: Indicates an error validating an SSL + * certificate + * + * SSL-related I/O errors. + **/ diff --git a/libsoup/soup-ssl.h b/libsoup/soup-ssl.h index f4e3eab..5858199 100644 --- a/libsoup/soup-ssl.h +++ b/libsoup/soup-ssl.h @@ -6,7 +6,7 @@ #ifndef SOUP_SSL_H #define SOUP_SSL_H 1 -#include +#include "soup-types.h" typedef enum { SOUP_SSL_TYPE_CLIENT = 0, @@ -15,17 +15,15 @@ typedef enum { typedef struct SoupSSLCredentials SoupSSLCredentials; -SoupSSLCredentials *soup_ssl_get_client_credentials (const char *ca_file); -void soup_ssl_free_client_credentials (SoupSSLCredentials *creds); +SoupSSLCredentials *soup_ssl_get_client_credentials (const char *ca_file); +void soup_ssl_free_client_credentials (SoupSSLCredentials *creds); +gboolean soup_ssl_credentials_verify_certificate (SoupSSLCredentials *creds, + GTlsCertificate *cert, + GTlsCertificateFlags errors); -SoupSSLCredentials *soup_ssl_get_server_credentials (const char *cert_file, - const char *key_file); -void soup_ssl_free_server_credentials (SoupSSLCredentials *creds); - -GIOChannel *soup_ssl_wrap_iochannel (GIOChannel *sock, - gboolean non_blocking, - SoupSSLType type, - const char *remote_host, - SoupSSLCredentials *creds); +SoupSSLCredentials *soup_ssl_get_server_credentials (const char *cert_file, + const char *key_file); +void soup_ssl_free_server_credentials (SoupSSLCredentials *creds); +GTlsCertificate *soup_ssl_credentials_get_certificate (SoupSSLCredentials *creds); #endif /* SOUP_SSL_H */ diff --git a/libsoup/soup-status.c b/libsoup/soup-status.c index 1581d7a..8a2653c 100644 --- a/libsoup/soup-status.c +++ b/libsoup/soup-status.c @@ -181,11 +181,7 @@ static const struct { { SOUP_STATUS_CANT_RESOLVE_PROXY, "Cannot resolve proxy hostname" }, { SOUP_STATUS_CANT_CONNECT, "Cannot connect to destination" }, { SOUP_STATUS_CANT_CONNECT_PROXY, "Cannot connect to proxy" }, -#ifdef HAVE_SSL { SOUP_STATUS_SSL_FAILED, "SSL handshake failed" }, -#else - { SOUP_STATUS_SSL_FAILED, "SSL support not available" }, -#endif { SOUP_STATUS_IO_ERROR, "Connection terminated unexpectedly" }, { SOUP_STATUS_MALFORMED, "Message Corrupt" }, { SOUP_STATUS_TOO_MANY_REDIRECTS, "Too many redirects" }, diff --git a/libsoup/soup-types.h b/libsoup/soup-types.h index 5d7cb3c..d022039 100644 --- a/libsoup/soup-types.h +++ b/libsoup/soup-types.h @@ -6,8 +6,7 @@ #ifndef SOUP_TYPES_H #define SOUP_TYPES_H 1 -#include -#include +#include #include diff --git a/tests/Makefile.am b/tests/Makefile.am index b69d27a..8316f77 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -4,8 +4,7 @@ INCLUDES = \ -DLIBSOUP_DISABLE_DEPRECATED \ $(SOUP_MAINTAINER_FLAGS) \ $(XML_CFLAGS) \ - $(GLIB_CFLAGS) \ - $(LIBGNUTLS_CFLAGS) + $(GLIB_CFLAGS) LIBS = \ $(top_builddir)/libsoup/libsoup-2.4.la \ @@ -35,7 +34,6 @@ noinst_PROGRAMS = \ uri-parsing \ $(CURL_TESTS) \ $(APACHE_TESTS) \ - $(SSL_TESTS) \ $(XMLRPC_TESTS) TEST_SRCS = test-utils.c test-utils.h @@ -65,7 +63,6 @@ server_auth_test_SOURCES = server-auth-test.c $(TEST_SRCS) simple_httpd_SOURCES = simple-httpd.c simple_proxy_SOURCES = simple-proxy.c sniffing_test_SOURCES = sniffing-test.c $(TEST_SRCS) -ssl_test_SOURCES = ssl-test.c $(TEST_SRCS) streaming_test_SOURCES = streaming-test.c $(TEST_SRCS) timeout_test_SOURCES = timeout-test.c $(TEST_SRCS) uri_parsing_SOURCES = uri-parsing.c $(TEST_SRCS) @@ -78,9 +75,6 @@ endif if HAVE_CURL CURL_TESTS = forms-test server-auth-test endif -if HAVE_SSL -SSL_TESTS = ssl-test -endif if HAVE_XMLRPC_EPI_PHP XMLRPC_TESTS = xmlrpc-test xmlrpc-server-test endif @@ -102,7 +96,6 @@ TESTS = \ uri-parsing \ $(APACHE_TESTS) \ $(CURL_TESTS) \ - $(SSL_TESTS) \ $(XMLRPC_TESTS) SNIFFING_FILES = \ diff --git a/tests/proxy-test.c b/tests/proxy-test.c index 68c1de8..4fb74ed 100644 --- a/tests/proxy-test.c +++ b/tests/proxy-test.c @@ -145,18 +145,12 @@ run_test (int i, gboolean sync) https_url = g_strconcat (HTTPS_SERVER, tests[i].url, NULL); } test_url (http_url, SIMPLE_PROXY, tests[i].final_status, sync, FALSE); -#ifdef HAVE_SSL test_url (https_url, SIMPLE_PROXY, tests[i].final_status, sync, FALSE); -#endif test_url (http_url, AUTH_PROXY, tests[i].final_status, sync, FALSE); -#ifdef HAVE_SSL test_url (https_url, AUTH_PROXY, tests[i].final_status, sync, FALSE); test_url (https_url, AUTH_PROXY, tests[i].final_status, sync, TRUE); -#endif test_url (http_url, UNAUTH_PROXY, tests[i].final_status, sync, FALSE); -#ifdef HAVE_SSL test_url (https_url, UNAUTH_PROXY, tests[i].final_status, sync, FALSE); -#endif g_free (http_url); g_free (https_url); diff --git a/tests/ssl-test.c b/tests/ssl-test.c deleted file mode 100644 index ce2237a..0000000 --- a/tests/ssl-test.c +++ /dev/null @@ -1,357 +0,0 @@ -#include -#include -#include -#include -#include -#include - -#include "libsoup/soup-address.h" -#include "libsoup/soup-socket.h" -#include "libsoup/soup-ssl.h" - -#define BUFSIZE 1024 -#define DH_BITS 1024 - -#ifndef G_OS_WIN32 -#define SOCKET_PRINT_ERROR(M) perror(M); -#else -#define SOCKET_PRINT_ERROR(M) g_error("%s: %d", M, WSAGetLastError()); -#endif - -static GMainLoop *loop; -static gnutls_dh_params_t dh_params; - -/* SERVER */ - -/* Read @bufsize bytes into @buf from @session. */ -static void -server_read (gnutls_session_t session, char *buf, int bufsize) -{ - int total, nread; - - total = 0; - while (total < bufsize) { - nread = gnutls_record_recv (session, buf + total, - bufsize - total); - if (nread <= 0) - g_error ("server read failed at position %d", total); - total += nread; - } -} - -/* Write @bufsize bytes from @buf to @session, forcing 3 rehandshakes - * along the way. (We do an odd number of rehandshakes to make sure - * they occur at weird times relative to the client's read buffer - * size.) - */ -static void -server_write (gnutls_session_t session, char *buf, int bufsize) -{ - int total, nwrote; - int next_rehandshake = bufsize / 3; - - total = 0; - while (total < bufsize) { - if (total >= next_rehandshake) { - if (gnutls_rehandshake (session) < 0) - g_error ("client refused rehandshake at position %d", total); - if (gnutls_handshake (session) < 0) - g_error ("server rehandshake failed at position %d", total); - next_rehandshake = MIN (bufsize, next_rehandshake + bufsize / 3); - } - - nwrote = gnutls_record_send (session, buf + total, - next_rehandshake - total); - if (nwrote <= 0) - g_error ("server write failed at position %d: %d", total, nwrote); - total += nwrote; - } -} - -static const char *ssl_cert_file = SRCDIR G_DIR_SEPARATOR_S "test-cert.pem"; -static const char *ssl_key_file = SRCDIR G_DIR_SEPARATOR_S "test-key.pem"; - -static gpointer -server_thread (gpointer user_data) -{ - int listener = GPOINTER_TO_INT (user_data), client; - gnutls_certificate_credentials creds; - gnutls_session_t session; - struct sockaddr_in sin; - int len; - char buf[BUFSIZE]; - int status; - - gnutls_certificate_allocate_credentials (&creds); - if (gnutls_certificate_set_x509_key_file (creds, - ssl_cert_file, ssl_key_file, - GNUTLS_X509_FMT_PEM) != 0) { - g_error ("Failed to set SSL certificate and key files " - "(%s, %s).", ssl_cert_file, ssl_key_file); - } - gnutls_certificate_set_dh_params (creds, dh_params); - - /* Create a new session */ - gnutls_init (&session, GNUTLS_SERVER); - gnutls_set_default_priority (session); - gnutls_credentials_set (session, GNUTLS_CRD_CERTIFICATE, creds); - gnutls_dh_set_prime_bits (session, DH_BITS); - - /* Wait for client thread to connect */ - len = sizeof (sin); - client = accept (listener, (struct sockaddr *) &sin, (void *)&len); - gnutls_transport_set_ptr (session, GINT_TO_POINTER (client)); - - /* Initial handshake */ - status = gnutls_handshake (session); - if (status < 0) - g_error ("initial handshake failed: %d", status); - - /* Synchronous client test. */ - server_read (session, buf, BUFSIZE); - server_write (session, buf, BUFSIZE); - - /* Async client test. */ - server_read (session, buf, BUFSIZE); - server_write (session, buf, BUFSIZE); - - /* That's all, folks. */ - gnutls_bye (session, GNUTLS_SHUT_WR); - gnutls_deinit (session); - close (client); - gnutls_certificate_free_credentials (creds); - - return NULL; -} - -/* async client code */ - -typedef struct { - char writebuf[BUFSIZE], readbuf[BUFSIZE]; - int total; -} AsyncData; - -static void -async_read (SoupSocket *sock, gpointer user_data) -{ - AsyncData *data = user_data; - SoupSocketIOStatus status; - gsize n; - GError *error = NULL; - - do { - status = soup_socket_read (sock, data->readbuf + data->total, - BUFSIZE - data->total, &n, - NULL, &error); - if (status == SOUP_SOCKET_OK) - data->total += n; - } while (status == SOUP_SOCKET_OK && data->total < BUFSIZE); - - if (status == SOUP_SOCKET_ERROR || status == SOUP_SOCKET_EOF) { - g_error ("Async read got status %d: %s", status, - error ? error->message : "(unknown)"); - } else if (status == SOUP_SOCKET_WOULD_BLOCK) - return; - - if (memcmp (data->writebuf, data->readbuf, BUFSIZE) != 0) - g_error ("Sync read didn't match write"); - - g_free (data); - g_main_loop_quit (loop); -} - -static void -async_write (SoupSocket *sock, gpointer user_data) -{ - AsyncData *data = user_data; - SoupSocketIOStatus status; - gsize n; - GError *error = NULL; - - do { - status = soup_socket_write (sock, data->writebuf + data->total, - BUFSIZE - data->total, &n, - NULL, &error); - if (status == SOUP_SOCKET_OK) - data->total += n; - } while (status == SOUP_SOCKET_OK && data->total < BUFSIZE); - - if (status == SOUP_SOCKET_ERROR || status == SOUP_SOCKET_EOF) { - g_error ("Async write got status %d: %s", status, - error ? error->message : "(unknown)"); - } else if (status == SOUP_SOCKET_WOULD_BLOCK) - return; - - data->total = 0; - async_read (sock, user_data); -} - -static gboolean -start_writing (gpointer user_data) -{ - SoupSocket *sock = user_data; - AsyncData *data; - int i; - - data = g_new (AsyncData, 1); - for (i = 0; i < BUFSIZE; i++) - data->writebuf[i] = i & 0xFF; - data->total = 0; - - g_signal_connect (sock, "writable", - G_CALLBACK (async_write), data); - g_signal_connect (sock, "readable", - G_CALLBACK (async_read), data); - - async_write (sock, data); - return FALSE; -} - -static void -debug_log (int level, const char *str) -{ - fputs (str, stderr); -} - -int -main (int argc, char **argv) -{ - int opt, debug = 0, listener, sin_len, port, i; - struct sockaddr_in sin; - GThread *server; - char writebuf[BUFSIZE], readbuf[BUFSIZE]; - SoupAddress *addr; - SoupSSLCredentials *creds; - SoupSocket *sock; - gsize n, total; - SoupSocketIOStatus status; - int connect_status; - GError *error = NULL; - - g_thread_init (NULL); - g_type_init (); - - /* On Windows, this will call WSAStartup() */ - soup_socket_get_type (); - - while ((opt = getopt (argc, argv, "c:d:k:")) != -1) { - switch (opt) { - case 'c': - ssl_cert_file = optarg; - break; - case 'd': - debug = atoi (optarg); - break; - case 'k': - ssl_key_file = optarg; - break; - - case '?': - fprintf (stderr, "Usage: %s [-d debuglevel] [-c ssl-cert-file] [-k ssl-key-file]\n", - argv[0]); - break; - } - } - - if (debug) { - gnutls_global_set_log_function (debug_log); - gnutls_global_set_log_level (debug); - } - - /* Create server socket */ - listener = socket (AF_INET, SOCK_STREAM, 0); - if (listener == -1) { - SOCKET_PRINT_ERROR ("creating listening socket"); - exit (1); - } - - memset (&sin, 0, sizeof (sin)); - sin.sin_family = AF_INET; - sin.sin_addr.s_addr = ntohl (INADDR_LOOPBACK); - - if (bind (listener, (struct sockaddr *) &sin, sizeof (sin)) == -1) { - SOCKET_PRINT_ERROR ("binding listening socket"); - exit (1); - } - - if (listen (listener, 1) == -1) { - SOCKET_PRINT_ERROR ("listening on socket"); - exit (1); - } - - sin_len = sizeof (sin); - getsockname (listener, (struct sockaddr *)&sin, (void *)&sin_len); - port = ntohs (sin.sin_port); - - /* Create the client */ - addr = soup_address_new ("127.0.0.1", port); - creds = soup_ssl_get_client_credentials (NULL); - sock = soup_socket_new (SOUP_SOCKET_REMOTE_ADDRESS, addr, - SOUP_SOCKET_FLAG_NONBLOCKING, FALSE, - SOUP_SOCKET_SSL_CREDENTIALS, creds, - NULL); - g_object_unref (addr); - connect_status = soup_socket_connect_sync (sock, NULL); - if (connect_status != SOUP_STATUS_OK) { - g_error ("Could not create client socket: %s", - soup_status_get_phrase (connect_status)); - } - - soup_socket_start_ssl (sock, NULL); - - /* Now spawn server thread */ - server = g_thread_create (server_thread, GINT_TO_POINTER (listener), - TRUE, NULL); - - /* Synchronous client test */ - for (i = 0; i < BUFSIZE; i++) - writebuf[i] = i & 0xFF; - - total = 0; - while (total < BUFSIZE) { - status = soup_socket_write (sock, writebuf + total, - BUFSIZE - total, &n, - NULL, &error); - if (status != SOUP_SOCKET_OK) - g_error ("Sync write got status %d: %s", status, - error ? error->message : "(unknown)"); - total += n; - } - - total = 0; - while (total < BUFSIZE) { - status = soup_socket_read (sock, readbuf + total, - BUFSIZE - total, &n, - NULL, &error); - if (status != SOUP_SOCKET_OK) - g_error ("Sync read got status %d: %s", status, - error ? error->message : "(unknown)"); - total += n; - } - - if (memcmp (writebuf, readbuf, BUFSIZE) != 0) - g_error ("Sync read didn't match write"); - - printf ("SYNCHRONOUS SSL TEST PASSED\n"); - - /* Switch socket to async and do it again */ - - g_object_set (sock, - SOUP_SOCKET_FLAG_NONBLOCKING, TRUE, - NULL); - - g_idle_add (start_writing, sock); - loop = g_main_loop_new (NULL, TRUE); - g_main_loop_run (loop); - g_main_loop_unref (loop); - g_main_context_unref (g_main_context_default ()); - - printf ("ASYNCHRONOUS SSL TEST PASSED\n"); - - g_object_unref (sock); - soup_ssl_free_client_credentials (creds); - g_thread_join (server); - - /* Success */ - return 0; -} diff --git a/tests/timeout-test.c b/tests/timeout-test.c index 53d54d9..5aec83d 100644 --- a/tests/timeout-test.c +++ b/tests/timeout-test.c @@ -176,8 +176,7 @@ main (int argc, char **argv) g_free (slow_uri); soup_test_server_quit_unref (server); -#ifdef HAVE_SSL - debug_printf (1, "https\n"); + debug_printf (1, "\nhttps\n"); server = soup_test_server_new_ssl (TRUE); soup_server_add_handler (server, NULL, server_handler, NULL, NULL); fast_uri = g_strdup_printf ("https://127.0.0.1:%u/", @@ -188,7 +187,6 @@ main (int argc, char **argv) g_free (fast_uri); g_free (slow_uri); soup_test_server_quit_unref (server); -#endif test_cleanup (); return errors != 0; -- 2.7.4