summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan Winship <danw@gnome.org>2009-11-12 19:44:27 -0500
committerDan Winship <danw@gnome.org>2010-12-07 11:23:05 +0100
commit97bacf3057b7c45c29a6d025c67a6dd588144e05 (patch)
tree08335adab4e6d66d10a8bb560773b9d98d067017
parentac667c1893aee87d07627fbc2181902ec3de1d79 (diff)
downloadlibsoup-97bacf3057b7c45c29a6d025c67a6dd588144e05.tar.gz
SoupSocket: port to GSocketConnection/GTlsConnection
and remove libsoup's built-in TLS support, which is no longer needed
-rw-r--r--README2
-rw-r--r--configure.ac40
-rw-r--r--libsoup-2.4.pc.in2
-rw-r--r--libsoup/Makefile.am10
-rw-r--r--libsoup/soup-address.h2
-rw-r--r--libsoup/soup-connection.h2
-rw-r--r--libsoup/soup-gnutls.c705
-rw-r--r--libsoup/soup-message-io.c2
-rw-r--r--libsoup/soup-message-queue.h3
-rw-r--r--libsoup/soup-nossl.c91
-rw-r--r--libsoup/soup-password-manager.h1
-rw-r--r--libsoup/soup-portability.h2
-rw-r--r--libsoup/soup-proxy-resolver.h1
-rw-r--r--libsoup/soup-socket.c598
-rw-r--r--libsoup/soup-socket.h1
-rw-r--r--libsoup/soup-ssl.c143
-rw-r--r--libsoup/soup-ssl.h22
-rw-r--r--libsoup/soup-status.c4
-rw-r--r--libsoup/soup-types.h3
-rw-r--r--tests/Makefile.am9
-rw-r--r--tests/proxy-test.c6
-rw-r--r--tests/ssl-test.c357
-rw-r--r--tests/timeout-test.c4
23 files changed, 382 insertions, 1628 deletions
diff --git a/README b/README
index bf3b70a6..8baf635b 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 5f475015..948651d0 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 7df813c0..13949390 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 4278f3d4..38c0a389 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 15c66fd7..a7023cbb 100644
--- a/libsoup/soup-address.h
+++ b/libsoup/soup-address.h
@@ -8,8 +8,6 @@
#include <sys/types.h>
-#include <gio/gio.h>
-
#include <libsoup/soup-portability.h>
#include <libsoup/soup-types.h>
diff --git a/libsoup/soup-connection.h b/libsoup/soup-connection.h
index 629676b2..ebdf9bc3 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 <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
index 0b57f281..00000000
--- 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 <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 */
diff --git a/libsoup/soup-message-io.c b/libsoup/soup-message-io.c
index 525ea71f..e824b00a 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 4f655b3c..08cc6dfc 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 <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
index 926854d4..00000000
--- 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 <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.
- **/
diff --git a/libsoup/soup-password-manager.h b/libsoup/soup-password-manager.h
index 75f5cd83..775f84c5 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 <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))
diff --git a/libsoup/soup-portability.h b/libsoup/soup-portability.h
index be00312c..b36e7d72 100644
--- a/libsoup/soup-portability.h
+++ b/libsoup/soup-portability.h
@@ -6,7 +6,7 @@
#ifndef SOUP_PORTABILITY_H
#define SOUP_PORTABILITY_H
-#include <glibconfig.h>
+#include <libsoup/soup-types.h>
#ifdef G_OS_WIN32
diff --git a/libsoup/soup-proxy-resolver.h b/libsoup/soup-proxy-resolver.h
index 991219f4..dd787143 100644
--- a/libsoup/soup-proxy-resolver.h
+++ b/libsoup/soup-proxy-resolver.h
@@ -7,7 +7,6 @@
#define SOUP_PROXY_RESOLVER_H 1
#include <libsoup/soup-types.h>
-#include <gio/gio.h>
G_BEGIN_DECLS
diff --git a/libsoup/soup-socket.c b/libsoup/soup-socket.c
index 4e658911..c7d5716c 100644
--- a/libsoup/soup-socket.c
+++ b/libsoup/soup-socket.c
@@ -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;
}
diff --git a/libsoup/soup-socket.h b/libsoup/soup-socket.h
index 2e039d95..058e9303 100644
--- a/libsoup/soup-socket.h
+++ b/libsoup/soup-socket.h
@@ -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
index 00000000..71c4dc1b
--- /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 <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.
+ **/
diff --git a/libsoup/soup-ssl.h b/libsoup/soup-ssl.h
index f4e3eab1..58581998 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 <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 */
diff --git a/libsoup/soup-status.c b/libsoup/soup-status.c
index 1581d7ae..8a2653ca 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 5d7cb3ce..d0220399 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 <glib.h>
-#include <glib-object.h>
+#include <gio/gio.h>
#include <libsoup/soup-status.h>
diff --git a/tests/Makefile.am b/tests/Makefile.am
index b69d27ad..8316f77f 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 68c1de80..4fb74ed5 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 ce2237a2..00000000
--- a/tests/ssl-test.c
+++ /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;
-}
diff --git a/tests/timeout-test.c b/tests/timeout-test.c
index 53d54d9a..5aec83d7 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;