SoupSocket: port to GSocketConnection/GTlsConnection
authorDan Winship <danw@gnome.org>
Fri, 13 Nov 2009 00:44:27 +0000 (19:44 -0500)
committerDan Winship <danw@gnome.org>
Tue, 7 Dec 2010 10:23:05 +0000 (11:23 +0100)
and remove libsoup's built-in TLS support, which is no longer needed

23 files changed:
README
configure.ac
libsoup-2.4.pc.in
libsoup/Makefile.am
libsoup/soup-address.h
libsoup/soup-connection.h
libsoup/soup-gnutls.c [deleted file]
libsoup/soup-message-io.c
libsoup/soup-message-queue.h
libsoup/soup-nossl.c [deleted file]
libsoup/soup-password-manager.h
libsoup/soup-portability.h
libsoup/soup-proxy-resolver.h
libsoup/soup-socket.c
libsoup/soup-socket.h
libsoup/soup-ssl.c [new file with mode: 0644]
libsoup/soup-ssl.h
libsoup/soup-status.c
libsoup/soup-types.h
tests/Makefile.am
tests/proxy-test.c
tests/ssl-test.c [deleted file]
tests/timeout-test.c

diff --git a/README b/README
index bf3b70a..8baf635 100644 (file)
--- 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
index 5f47501..948651d 100644 (file)
@@ -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)]),
index 7df813c..1394939 100644 (file)
@@ -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
index 4278f3d..38c0a38 100644 (file)
@@ -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              \
index 15c66fd..a7023cb 100644 (file)
@@ -8,8 +8,6 @@
 
 #include <sys/types.h>
 
-#include <gio/gio.h>
-
 #include <libsoup/soup-portability.h>
 #include <libsoup/soup-types.h>
 
index 629676b..ebdf9bc 100644 (file)
@@ -6,8 +6,6 @@
 #ifndef SOUP_CONNECTION_H
 #define SOUP_CONNECTION_H 1
 
-#include <gio/gio.h>
-
 #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 (file)
index 0b57f28..0000000
+++ /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 <config.h>
-#endif
-
-#ifdef HAVE_SSL
-
-#include <errno.h>
-#include <fcntl.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include <glib.h>
-
-#ifndef G_OS_WIN32
-#include <pthread.h>
-#endif
-
-#include <gcrypt.h>
-#include <gnutls/gnutls.h>
-#include <gnutls/x509.h>
-
-#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 */
index 525ea71..e824b00 100644 (file)
@@ -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);
index 4f655b3..08cc6df 100644 (file)
@@ -7,9 +7,6 @@
 #ifndef SOUP_MESSAGE_QUEUE_H
 #define SOUP_MESSAGE_QUEUE_H 1
 
-#include <glib.h>
-#include <gio/gio.h>
-
 #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 (file)
index 926854d..0000000
+++ /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 <config.h>
-#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.
- **/
index 75f5cd8..775f84c 100644 (file)
@@ -9,7 +9,6 @@
 #ifdef LIBSOUP_I_HAVE_READ_BUG_594377_AND_KNOW_SOUP_PASSWORD_MANAGER_MIGHT_GO_AWAY
 
 #include <libsoup/soup-types.h>
-#include <gio/gio.h>
 
 #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))
index be00312..b36e7d7 100644 (file)
@@ -6,7 +6,7 @@
 #ifndef SOUP_PORTABILITY_H
 #define SOUP_PORTABILITY_H
 
-#include <glibconfig.h>
+#include <libsoup/soup-types.h>
 
 #ifdef G_OS_WIN32
 
index 991219f..dd78714 100644 (file)
@@ -7,7 +7,6 @@
 #define SOUP_PROXY_RESOLVER_H 1
 
 #include <libsoup/soup-types.h>
-#include <gio/gio.h>
 
 G_BEGIN_DECLS
 
index 4e65891..c7d5716 100644 (file)
@@ -22,9 +22,6 @@
 #include "soup-misc.h"
 #include "soup-ssl.h"
 
-#include <sys/time.h>
-#include <sys/types.h>
-
 /**
  * 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;
 }
index 2e039d9..058e930 100644 (file)
@@ -7,7 +7,6 @@
 #define SOUP_SOCKET_H 1
 
 #include <libsoup/soup-types.h>
-#include <gio/gio.h>
 
 G_BEGIN_DECLS
 
diff --git a/libsoup/soup-ssl.c b/libsoup/soup-ssl.c
new file mode 100644 (file)
index 0000000..71c4dc1
--- /dev/null
@@ -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 <config.h>
+#endif
+
+#include <gio/gio.h>
+
+#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.
+ **/
index f4e3eab..5858199 100644 (file)
@@ -6,7 +6,7 @@
 #ifndef SOUP_SSL_H
 #define SOUP_SSL_H 1
 
-#include <glib.h>
+#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 */
index 1581d7a..8a2653c 100644 (file)
@@ -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" },
index 5d7cb3c..d022039 100644 (file)
@@ -6,8 +6,7 @@
 #ifndef SOUP_TYPES_H
 #define SOUP_TYPES_H 1
 
-#include <glib.h>
-#include <glib-object.h>
+#include <gio/gio.h>
 
 #include <libsoup/soup-status.h>
 
index b69d27a..8316f77 100644 (file)
@@ -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 =               \
index 68c1de8..4fb74ed 100644 (file)
@@ -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 (file)
index ce2237a..0000000
+++ /dev/null
@@ -1,357 +0,0 @@
-#include <gnutls/gnutls.h>
-#include <glib.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#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;
-}
index 53d54d9..5aec83d 100644 (file)
@@ -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;