[libsoup/tls] SoupSocket: port to GSocketConnection/GTlsConnection
- From: Dan Winship <danw src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [libsoup/tls] SoupSocket: port to GSocketConnection/GTlsConnection
- Date: Wed, 1 Dec 2010 01:49:30 +0000 (UTC)
commit 98b2ff3e7cba54cd9bdc3aadf91a60c011eee580
Author: Dan Winship <danw gnome org>
Date: Thu Nov 12 19:44:27 2009 -0500
SoupSocket: port to GSocketConnection/GTlsConnection
and remove libsoup's built-in TLS support, which is no longer needed
README | 2 +-
configure.ac | 36 ---
libsoup-2.4.pc.in | 2 +-
libsoup/Makefile.am | 10 +-
libsoup/soup-gnutls.c | 705 ---------------------------------------------
libsoup/soup-message-io.c | 2 +-
libsoup/soup-nossl.c | 91 ------
libsoup/soup-socket.c | 497 +++++++++++---------------------
libsoup/soup-ssl.c | 143 +++++++++
libsoup/soup-ssl.h | 22 +-
libsoup/soup-status.c | 4 -
tests/Makefile.am | 9 +-
tests/proxy-test.c | 6 -
tests/ssl-test.c | 357 -----------------------
tests/timeout-test.c | 2 -
15 files changed, 333 insertions(+), 1555 deletions(-)
---
diff --git a/README b/README
index bf3b70a..8baf635 100644
--- a/README
+++ b/README
@@ -4,7 +4,7 @@ and the glib main loop, to integrate well with GNOME applications.
Features:
* Both asynchronous (GMainLoop and callback-based) and synchronous APIs
* Automatically caches connections
- * SSL Support using GnuTLS
+ * SSL support
* Proxy support, including authentication and SSL tunneling
* Client support for Digest, NTLM, and Basic authentication
* Server support for Digest and Basic authentication
diff --git a/configure.ac b/configure.ac
index 1819a5c..4781cc2 100644
--- a/configure.ac
+++ b/configure.ac
@@ -106,39 +106,6 @@ AC_CHECK_FUNCS(gmtime_r)
AC_CHECK_FUNCS(mmap)
AC_CHECK_FUNC(socket, , AC_CHECK_LIB(socket, socket))
-dnl **********************************
-dnl *** SSL Library check (GnuTLS) ***
-dnl **********************************
-
-AC_ARG_ENABLE(ssl,
- AS_HELP_STRING([--disable-ssl], [Disable SSL/TLS support (not recommended)]),,
- enable_ssl=auto)
-
-have_ssl=no
-if test "$enable_ssl" != "no"; then
- PKG_CHECK_MODULES(LIBGNUTLS, gnutls >= 2.1.7,
- [AM_PATH_LIBGCRYPT([], have_ssl=yes, have_ssl=no)], have_ssl=no)
-fi
-if test "$have_ssl" = "yes"; then
- AC_DEFINE(HAVE_SSL, 1, [Defined if you have SSL support])
- SSL_REQUIREMENT="gnutls"
-else
- if test "$enable_ssl" = "no"; then
- AC_MSG_WARN(Disabling SSL support);
- else
- AC_MSG_ERROR([Could not configure SSL support.
-Pass "--disable-ssl" if you really want to build without SSL support]);
- fi
-fi
-
-AC_SUBST(LIBGNUTLS_CFLAGS)
-AC_SUBST(LIBGNUTLS_LIBS)
-AC_SUBST(SSL_REQUIREMENT)
-
-dnl This is not supposed to be conditional, but...
-AM_CONDITIONAL(HAVE_SSL, test $enable_ssl != no)
-
-
dnl *********************
dnl *** GNOME support ***
dnl *********************
@@ -256,9 +223,6 @@ dnl *** Stuff for regression tests
dnl ******************************
AC_MSG_NOTICE([checking for programs needed for regression tests])
MISSING_REGRESSION_TEST_PACKAGES=""
-if test $have_ssl = "no"; then
- MISSING_REGRESSION_TEST_PACKAGES=" gnutls"
-fi
AC_ARG_WITH(apache-httpd,
AS_HELP_STRING([--with-apache-httpd], [Path to apache httpd (for tests)]),
diff --git a/libsoup-2.4.pc.in b/libsoup-2.4.pc.in
index 7df813c..1394939 100644
--- a/libsoup-2.4.pc.in
+++ b/libsoup-2.4.pc.in
@@ -7,6 +7,6 @@ Name: libsoup
Description: a glib-based HTTP library
Version: @VERSION@
Requires: glib-2.0 gobject-2.0 gio-2.0
-Requires.private: libxml-2.0 @SSL_REQUIREMENT@
+Requires.private: libxml-2.0
Libs: -L${libdir} -lsoup-2.4
Cflags: -I${includedir}/libsoup-2.4
diff --git a/libsoup/Makefile.am b/libsoup/Makefile.am
index d602916..f40233f 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-message-io.c b/libsoup/soup-message-io.c
index 525ea71..e824b00 100644
--- a/libsoup/soup-message-io.c
+++ b/libsoup/soup-message-io.c
@@ -185,7 +185,7 @@ io_error (SoupSocket *sock, SoupMessage *msg, GError *error)
SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
SoupMessageIOData *io = priv->io_data;
- if (error && error->domain == SOUP_SSL_ERROR) {
+ if (error && error->domain == G_TLS_ERROR) {
soup_message_set_status_full (msg,
SOUP_STATUS_SSL_FAILED,
error->message);
diff --git a/libsoup/soup-socket.c b/libsoup/soup-socket.c
index 4e65891..26176d1 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
@@ -67,12 +64,13 @@ 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 +79,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;
@@ -97,11 +94,9 @@ 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
@@ -120,13 +115,13 @@ soup_socket_init (SoupSocket *sock)
static void
disconnect_internal (SoupSocketPrivate *priv)
{
- if (priv->iochannel) {
- g_io_channel_unref (priv->iochannel);
- priv->iochannel = NULL;
- }
if (priv->conn) {
g_object_unref (priv->conn);
priv->conn = NULL;
+ g_object_unref (priv->gsock);
+ priv->gsock = NULL;
+ priv->istream = NULL;
+ priv->ostream = NULL;
}
priv->sockfd = -1;
@@ -138,14 +133,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 +145,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 +411,28 @@ soup_socket_class_init (SoupSocketClass *socket_class)
static void
-set_nonblocking (SoupSocketPrivate *priv)
-{
-#ifndef G_OS_WIN32
- int flags;
-#else
- u_long val;
-#endif
-
- if (priv->sockfd == -1)
- 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
-}
-
-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
+ if (!priv->conn) {
+ priv->gsock = g_socket_new_from_fd (priv->sockfd, NULL);
+ priv->conn = (GIOStream *)g_socket_connection_factory_create_connection (priv->gsock);
+ }
-#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);
+ if (!priv->istream) {
+ 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));
+ }
+
+ g_socket_set_timeout (priv->gsock, priv->timeout);
}
static void
@@ -528,7 +450,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 +467,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 +547,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,13 +561,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);
+ priv->conn = (GIOStream *)conn;
+ priv->gsock = g_object_ref (g_socket_connection_get_socket (conn));
+ priv->sockfd = g_socket_get_fd (priv->gsock);
set_fdflags (priv);
return SOUP_STATUS_OK;
@@ -725,14 +643,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,
@@ -774,14 +686,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);
@@ -798,23 +704,38 @@ soup_socket_get_fd (SoupSocket *sock)
return SOUP_SOCKET_GET_PRIVATE (sock)->sockfd;
}
+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;
- if (condition & (G_IO_HUP | G_IO_ERR)) {
- priv->watch_src = NULL;
- return FALSE;
- }
+ /* Using g_socket_accept() here would require more rewriting... */
sa_len = sizeof (sa);
sockfd = accept (priv->sockfd, (struct sockaddr *)&sa, (void *)&sa_len);
if (SOUP_IS_INVALID_SOCKET (sockfd))
- return TRUE;
+ return FALSE;
new = g_object_new (SOUP_TYPE_SOCKET, NULL);
new_priv = SOUP_SOCKET_GET_PRIVATE (new);
@@ -823,7 +744,8 @@ listen_watch (GIOChannel* iochannel, GIOCondition condition, gpointer data)
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;
+ if (priv->ssl_creds)
+ 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);
@@ -856,8 +778,6 @@ 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);
@@ -876,39 +796,52 @@ 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);
+ priv->sockfd = socket (g_socket_address_get_family (addr),
+ SOCK_STREAM, 0);
if (SOUP_IS_INVALID_SOCKET (priv->sockfd))
goto cant_listen;
set_fdflags (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 +875,46 @@ 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);
-
- 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_tls_client_connection_new (priv->conn, identity, 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_tls_server_connection_new (priv->conn,
+ soup_ssl_credentials_get_certificate (priv->ssl_creds),
+ NULL);
- priv->iochannel = ssl_chan;
- g_io_channel_unref (real_chan);
+ if (!conn)
+ return FALSE;
+
+ 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,7 +956,7 @@ 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;
@@ -1013,7 +965,7 @@ soup_socket_disconnect (SoupSocket *sock)
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.)
@@ -1062,7 +1014,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;
}
/**
@@ -1127,128 +1079,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 +1212,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 +1277,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 +1308,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 +1350,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 +1360,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-ssl.c b/libsoup/soup-ssl.c
new file mode 100644
index 0000000..71c4dc1
--- /dev/null
+++ b/libsoup/soup-ssl.c
@@ -0,0 +1,143 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * soup-ssl.c: temporary ssl integration
+ *
+ * Copyright (C) 2010 Red Hat, Inc.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <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 f4e3eab..07a5dbb 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 <gio/gio.h>
typedef enum {
SOUP_SSL_TYPE_CLIENT = 0,
@@ -15,17 +15,15 @@ typedef enum {
typedef struct SoupSSLCredentials SoupSSLCredentials;
-SoupSSLCredentials *soup_ssl_get_client_credentials (const char *ca_file);
-void soup_ssl_free_client_credentials (SoupSSLCredentials *creds);
+SoupSSLCredentials *soup_ssl_get_client_credentials (const char *ca_file);
+void soup_ssl_free_client_credentials (SoupSSLCredentials *creds);
+gboolean soup_ssl_credentials_verify_certificate (SoupSSLCredentials *creds,
+ GTlsCertificate *cert,
+ GTlsCertificateFlags errors);
-SoupSSLCredentials *soup_ssl_get_server_credentials (const char *cert_file,
- const char *key_file);
-void soup_ssl_free_server_credentials (SoupSSLCredentials *creds);
-
-GIOChannel *soup_ssl_wrap_iochannel (GIOChannel *sock,
- gboolean non_blocking,
- SoupSSLType type,
- const char *remote_host,
- SoupSSLCredentials *creds);
+SoupSSLCredentials *soup_ssl_get_server_credentials (const char *cert_file,
+ const char *key_file);
+void soup_ssl_free_server_credentials (SoupSSLCredentials *creds);
+GTlsCertificate *soup_ssl_credentials_get_certificate (SoupSSLCredentials *creds);
#endif /* SOUP_SSL_H */
diff --git a/libsoup/soup-status.c b/libsoup/soup-status.c
index 1581d7a..8a2653c 100644
--- a/libsoup/soup-status.c
+++ b/libsoup/soup-status.c
@@ -181,11 +181,7 @@ static const struct {
{ SOUP_STATUS_CANT_RESOLVE_PROXY, "Cannot resolve proxy hostname" },
{ SOUP_STATUS_CANT_CONNECT, "Cannot connect to destination" },
{ SOUP_STATUS_CANT_CONNECT_PROXY, "Cannot connect to proxy" },
-#ifdef HAVE_SSL
{ SOUP_STATUS_SSL_FAILED, "SSL handshake failed" },
-#else
- { SOUP_STATUS_SSL_FAILED, "SSL support not available" },
-#endif
{ SOUP_STATUS_IO_ERROR, "Connection terminated unexpectedly" },
{ SOUP_STATUS_MALFORMED, "Message Corrupt" },
{ SOUP_STATUS_TOO_MANY_REDIRECTS, "Too many redirects" },
diff --git a/tests/Makefile.am b/tests/Makefile.am
index b69d27a..8316f77 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -4,8 +4,7 @@ INCLUDES = \
-DLIBSOUP_DISABLE_DEPRECATED \
$(SOUP_MAINTAINER_FLAGS) \
$(XML_CFLAGS) \
- $(GLIB_CFLAGS) \
- $(LIBGNUTLS_CFLAGS)
+ $(GLIB_CFLAGS)
LIBS = \
$(top_builddir)/libsoup/libsoup-2.4.la \
@@ -35,7 +34,6 @@ noinst_PROGRAMS = \
uri-parsing \
$(CURL_TESTS) \
$(APACHE_TESTS) \
- $(SSL_TESTS) \
$(XMLRPC_TESTS)
TEST_SRCS = test-utils.c test-utils.h
@@ -65,7 +63,6 @@ server_auth_test_SOURCES = server-auth-test.c $(TEST_SRCS)
simple_httpd_SOURCES = simple-httpd.c
simple_proxy_SOURCES = simple-proxy.c
sniffing_test_SOURCES = sniffing-test.c $(TEST_SRCS)
-ssl_test_SOURCES = ssl-test.c $(TEST_SRCS)
streaming_test_SOURCES = streaming-test.c $(TEST_SRCS)
timeout_test_SOURCES = timeout-test.c $(TEST_SRCS)
uri_parsing_SOURCES = uri-parsing.c $(TEST_SRCS)
@@ -78,9 +75,6 @@ endif
if HAVE_CURL
CURL_TESTS = forms-test server-auth-test
endif
-if HAVE_SSL
-SSL_TESTS = ssl-test
-endif
if HAVE_XMLRPC_EPI_PHP
XMLRPC_TESTS = xmlrpc-test xmlrpc-server-test
endif
@@ -102,7 +96,6 @@ TESTS = \
uri-parsing \
$(APACHE_TESTS) \
$(CURL_TESTS) \
- $(SSL_TESTS) \
$(XMLRPC_TESTS)
SNIFFING_FILES = \
diff --git a/tests/proxy-test.c b/tests/proxy-test.c
index 68c1de8..4fb74ed 100644
--- a/tests/proxy-test.c
+++ b/tests/proxy-test.c
@@ -145,18 +145,12 @@ run_test (int i, gboolean sync)
https_url = g_strconcat (HTTPS_SERVER, tests[i].url, NULL);
}
test_url (http_url, SIMPLE_PROXY, tests[i].final_status, sync, FALSE);
-#ifdef HAVE_SSL
test_url (https_url, SIMPLE_PROXY, tests[i].final_status, sync, FALSE);
-#endif
test_url (http_url, AUTH_PROXY, tests[i].final_status, sync, FALSE);
-#ifdef HAVE_SSL
test_url (https_url, AUTH_PROXY, tests[i].final_status, sync, FALSE);
test_url (https_url, AUTH_PROXY, tests[i].final_status, sync, TRUE);
-#endif
test_url (http_url, UNAUTH_PROXY, tests[i].final_status, sync, FALSE);
-#ifdef HAVE_SSL
test_url (https_url, UNAUTH_PROXY, tests[i].final_status, sync, FALSE);
-#endif
g_free (http_url);
g_free (https_url);
diff --git a/tests/timeout-test.c b/tests/timeout-test.c
index 53d54d9..db9dd8d 100644
--- a/tests/timeout-test.c
+++ b/tests/timeout-test.c
@@ -176,7 +176,6 @@ main (int argc, char **argv)
g_free (slow_uri);
soup_test_server_quit_unref (server);
-#ifdef HAVE_SSL
debug_printf (1, "https\n");
server = soup_test_server_new_ssl (TRUE);
soup_server_add_handler (server, NULL, server_handler, NULL, NULL);
@@ -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;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]