[libsoup/gresolver] checkpoint



commit 6a9489d1b21bf7a5b45abf40a8b4b5af50f17883
Author: Dan Winship <danw gnome org>
Date:   Tue Jun 23 19:07:05 2009 -0400

    checkpoint

 libsoup/soup-gnutls.c |   99 ++++++------------
 libsoup/soup-socket.c |  273 ++++++++++++++++++-------------------------------
 libsoup/soup-ssl.h    |   15 +++-
 3 files changed, 148 insertions(+), 239 deletions(-)
---
diff --git a/libsoup/soup-gnutls.c b/libsoup/soup-gnutls.c
index b5a5f32..c44a89c 100644
--- a/libsoup/soup-gnutls.c
+++ b/libsoup/soup-gnutls.c
@@ -171,33 +171,26 @@ again:
 	return G_IO_STATUS_NORMAL;
 }
 
-static GIOStatus
-soup_gnutls_read (GIOChannel   *channel,
-		  gchar        *buf,
-		  gsize         count,
-		  gsize        *bytes_read,
-		  GError      **err)
+gssize
+soup_ssl_session_receive (SoupSSLSession *session,
+			  gchar *buffer, gsize size,
+			  GCancellable *cancellable,
+			  GError **error)
 {
-	SoupGNUTLSChannel *chan = (SoupGNUTLSChannel *) channel;
-	gint result;
-
-	*bytes_read = 0;
+	int result;
+	gssize nread = 0;
 
 again:
-	if (!chan->established) {
-		result = do_handshake (chan, err);
+	if (!session->established) {
+		if (!do_handshake (session, error))
+			return -1;
 
-		if (result == G_IO_STATUS_AGAIN ||
-		    result == G_IO_STATUS_ERROR)
-			return result;
-
-		chan->established = TRUE;
+		session->established = TRUE;
 	}
 
-	result = gnutls_record_recv (chan->session, buf, count);
-
+	result = gnutls_record_recv (session->gnutls_session, buffer, size);
 	if (result == GNUTLS_E_REHANDSHAKE) {
-		chan->established = FALSE;
+		session->established = FALSE;
 		goto again;
 	}
 
@@ -407,40 +400,17 @@ soup_gnutls_push_func (gnutls_transport_ptr_t transport_data,
 	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)
+SoupSSLSession *
+soup_ssl_session_new (GSocket *gsock, SoupSSLType type,
+		      const char *remote_host, SoupSSLCredentials *creds)
 {
-	SoupGNUTLSChannel *chan = NULL;
-	GIOChannel *gchan = NULL;
+	SoupSSLSession *sss = NULL;
 	gnutls_session session = NULL;
-	int sockfd;
 	int ret;
 
-	g_return_val_if_fail (sock != NULL, NULL);
+	g_return_val_if_fail (gsock != 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)
@@ -456,27 +426,18 @@ soup_ssl_wrap_iochannel (GIOChannel *sock, gboolean non_blocking,
 	if (type == SOUP_SSL_TYPE_SERVER)
 		gnutls_dh_set_prime_bits (session, DH_BITS);
 
-	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);
+	sss = g_slice_new0 (SoupSSLSession);
+	sss->gsock = g_object_ref (gsock);
+	sss->session = session;
+	sss->creds = creds;
+	sss->hostname = g_strdup (remote_host);
+	sss->type = type;
+
+	gnutls_transport_set_ptr (session, sss);
 	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;
+	return sss;
 
  THROW_CREATE_ERROR:
 	if (session)
@@ -484,6 +445,12 @@ soup_ssl_wrap_iochannel (GIOChannel *sock, gboolean non_blocking,
 	return NULL;
 }
 
+gssize              soup_ssl_session_send            (SoupSSLSession     *session,
+						      const gchar        *buffer,
+						      gsize               size,
+						      GCancellable       *cancellable,
+						      GError            **error);
+
 #if defined(GCRY_THREAD_OPTION_PTHREAD_IMPL) && !defined(G_OS_WIN32)
 GCRY_THREAD_OPTION_PTHREAD_IMPL;
 #endif
diff --git a/libsoup/soup-socket.c b/libsoup/soup-socket.c
index 51a0668..cc114bb 100644
--- a/libsoup/soup-socket.c
+++ b/libsoup/soup-socket.c
@@ -64,7 +64,7 @@ enum {
 typedef struct {
 	int sockfd;
 	SoupAddress *local_addr, *remote_addr;
-	GIOChannel *iochannel;
+	GSocket *gsock;
 
 	guint non_blocking:1;
 	guint is_server:1;
@@ -82,12 +82,6 @@ typedef struct {
 } SoupSocketPrivate;
 #define SOUP_SOCKET_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), SOUP_TYPE_SOCKET, SoupSocketPrivate))
 
-#ifdef HAVE_IPV6
-#define soup_sockaddr_max sockaddr_in6
-#else
-#define soup_sockaddr_max sockaddr_in
-#endif
-
 static void set_property (GObject *object, guint prop_id,
 			  const GValue *value, GParamSpec *pspec);
 static void get_property (GObject *object, guint prop_id,
@@ -121,8 +115,8 @@ soup_socket_init (SoupSocket *sock)
 static void
 disconnect_internal (SoupSocketPrivate *priv)
 {
-	g_io_channel_unref (priv->iochannel);
-	priv->iochannel = NULL;
+	g_object_unref (priv->gsock);
+	priv->gsock = NULL;
 	priv->sockfd = -1;
 
 	if (priv->read_src) {
@@ -148,7 +142,7 @@ finalize (GObject *object)
 {
 	SoupSocketPrivate *priv = SOUP_SOCKET_GET_PRIVATE (object);
 
-	if (priv->iochannel)
+	if (priv->gsock)
 		disconnect_internal (priv);
 
 	if (priv->local_addr)
@@ -175,10 +169,6 @@ soup_socket_class_init (SoupSocketClass *socket_class)
 {
 	GObjectClass *object_class = G_OBJECT_CLASS (socket_class);
 
-#ifdef SIGPIPE
-	signal (SIGPIPE, SIG_IGN);
-#endif
-
 	g_type_class_add_private (socket_class, sizeof (SoupSocketPrivate));
 
 	/* virtual method override */
@@ -373,42 +363,10 @@ soup_socket_class_init (SoupSocketClass *socket_class)
 				   "Value in seconds to timeout a blocking I/O",
 				   0, G_MAXUINT, 0,
 				   G_PARAM_READWRITE));
-
-#ifdef G_OS_WIN32
-	/* Make sure WSAStartup() gets called. */
-	soup_address_get_type ();
-#endif
 }
 
 
 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;
@@ -420,21 +378,9 @@ set_fdflags (SoupSocketPrivate *priv)
 	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;
@@ -459,16 +405,8 @@ set_fdflags (SoupSocketPrivate *priv)
 		    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, TRUE);
-	g_io_channel_set_encoding (priv->iochannel, NULL, NULL);
-	g_io_channel_set_buffered (priv->iochannel, FALSE);
+	priv->gsock = g_socket_new_from_fd (priv->sockfd, NULL);
+	g_socket_set_blocking (priv->gsock, !priv->non_blocking);
 }
 
 static void
@@ -486,7 +424,8 @@ set_property (GObject *object, guint prop_id,
 		break;
 	case PROP_NON_BLOCKING:
 		priv->non_blocking = g_value_get_boolean (value);
-		set_nonblocking (priv);
+		if (priv->gsock)
+			g_socket_set_blocking (priv->gsock, !priv->non_blocking);
 		break;
 	case PROP_SSL_CREDENTIALS:
 		priv->ssl_creds = g_value_get_pointer (value);
@@ -566,7 +505,6 @@ soup_socket_new (const char *optname1, ...)
 typedef struct {
 	SoupSocket *sock;
 	GCancellable *cancellable;
-	guint cancel_id;
 	SoupSocketCallback callback;
 	gpointer user_data;
 } SoupSocketAsyncConnectData;
@@ -579,8 +517,6 @@ idle_connect_result (gpointer user_data)
 	guint status;
 
 	priv->watch_src = NULL;
-	if (sacd->cancel_id)
-		g_signal_handler_disconnect (sacd->cancellable, sacd->cancel_id);
 
 	if (priv->sockfd == -1) {
 		if (g_cancellable_is_cancelled (sacd->cancellable))
@@ -596,21 +532,13 @@ idle_connect_result (gpointer user_data)
 }
 
 static gboolean
-connect_watch (GIOChannel* iochannel, GIOCondition condition, gpointer data)
+connect_watch (GSocket *sock, GIOCondition condition, gpointer data)
 {
 	SoupSocketAsyncConnectData *sacd = data;
 	SoupSocketPrivate *priv = SOUP_SOCKET_GET_PRIVATE (sacd->sock);
-	int error = 0;
-	int len = sizeof (error);
 
-	/* Remove the watch now in case we don't return immediately */
-	g_source_destroy (priv->watch_src);
-	priv->watch_src = NULL;
-
-	if ((condition & ~(G_IO_IN | G_IO_OUT)) ||
-	    (getsockopt (priv->sockfd, SOL_SOCKET, SO_ERROR,
-			 (void *)&error, (void *)&len) != 0) ||
-	    error)
+	if (g_cancellable_is_cancelled (sacd->cancellable) ||
+	    !g_socket_check_connect_result (priv->gsock))
 		disconnect_internal (priv);
 
 	return idle_connect_result (sacd);
@@ -632,45 +560,61 @@ got_address (SoupAddress *addr, guint status, gpointer user_data)
 	g_slice_free (SoupSocketAsyncConnectData, sacd);
 }
 
-static void
-async_cancel (GCancellable *cancellable, gpointer user_data)
-{
-	SoupSocketAsyncConnectData *sacd = user_data;
-	SoupSocketPrivate *priv = SOUP_SOCKET_GET_PRIVATE (sacd->sock);
-
-	if (priv->watch_src)
-		g_source_destroy (priv->watch_src);
-	disconnect_internal (priv);
-	priv->watch_src = soup_add_completion (priv->async_context,
-					       idle_connect_result, sacd);
-}
-
 static guint
-socket_connect_internal (SoupSocket *sock)
+socket_connect_internal (SoupSocket *sock, GCancellable *cancellable)
 {
 	SoupSocketPrivate *priv = SOUP_SOCKET_GET_PRIVATE (sock);
-	struct sockaddr *sa;
-	int len, status;
+	GSocketAddress *addr;
+	GError *error = NULL;
+	int status;
 
-	sa = soup_address_get_sockaddr (priv->remote_addr, &len);
-	if (!sa)
+	addr = soup_address_get_gsockaddr (priv->remote_addr);
+	if (!addr)
 		return SOUP_STATUS_CANT_RESOLVE;
 
-	priv->sockfd = socket (sa->sa_family, SOCK_STREAM, 0);
+	priv->sockfd = socket (soup_address_get_family (priv->remote_addr),
+			       SOCK_STREAM, 0);
 	if (SOUP_IS_INVALID_SOCKET (priv->sockfd))
 		return SOUP_STATUS_CANT_CONNECT;
 	set_fdflags (priv);
 
-	status = connect (priv->sockfd, sa, len);
+	if (priv->non_blocking) {
+		if (g_socket_connect (priv->gsock, addr, &error))
+			return SOUP_STATUS_OK;
 
-	if (SOUP_IS_SOCKET_ERROR (status)) {
-		if (SOUP_IS_CONNECT_STATUS_INPROGRESS ())
+		if (error->domain == G_IO_ERROR &&
+		    error->code == G_IO_ERROR_PENDING) {
+			g_error_free (error);
 			return SOUP_STATUS_CONTINUE;
+		}
+		g_error_free (error);
+	} else {
+		if (!g_socket_condition_wait (priv->gsock, G_IO_OUT,
+					      cancellable, NULL)) {
+			disconnect_internal (priv);
+			return SOUP_STATUS_CANCELLED;
+		}
+		if (g_socket_connect (priv->gsock, addr, NULL))
+			return SOUP_STATUS_OK;
+	}
 
-		disconnect_internal (priv);
-		return SOUP_STATUS_CANT_CONNECT;
-	} else
-		return SOUP_STATUS_OK;
+	disconnect_internal (priv);
+	return SOUP_STATUS_CANT_CONNECT;
+}
+
+static GSource *
+soup_socket_create_watch (SoupSocketPrivate *priv, GIOCondition cond,
+			  GIOFunc callback, gpointer user_data,
+			  GCancellable *cancellable)
+{
+	GSource *watch;
+
+	watch = g_socket_create_source (priv->gsock, cond, cancellable);
+	g_source_set_callback (watch, callback, user_data);
+	g_source_attach (watch, priv->async_context);
+	g_source_unref (watch);
+
+	return watch;
 }
 
 /**
@@ -723,36 +667,22 @@ soup_socket_connect_async (SoupSocket *sock, GCancellable *cancellable,
 		return;
 	}
 
-	status = socket_connect_internal (sock);
+	status = socket_connect_internal (sock, NULL);
 	if (status == SOUP_STATUS_CONTINUE) {
 		/* Wait for connect to succeed or fail */
 		priv->watch_src =
-			soup_add_io_watch (priv->async_context,
-					   priv->iochannel,
-					   G_IO_IN | G_IO_OUT |
-					   G_IO_PRI | G_IO_ERR |
-					   G_IO_HUP | G_IO_NVAL,
-					   connect_watch, sacd);
-		if (cancellable) {
-			sacd->cancel_id =
-				g_signal_connect (cancellable, "cancelled",
-						  G_CALLBACK (async_cancel),
-						  sacd);
-		}
+			soup_socket_create_watch (priv,
+						  G_IO_IN | G_IO_OUT |
+						  G_IO_PRI | G_IO_ERR |
+						  G_IO_HUP | G_IO_NVAL,
+						  connect_watch, sacd,
+						  cancellable);
 	} else {
 		priv->watch_src = soup_add_completion (priv->async_context,
 						       idle_connect_result, sacd);
 	}
 }
 
-static void
-sync_cancel (GCancellable *cancellable, gpointer sock)
-{
-	SoupSocketPrivate *priv = SOUP_SOCKET_GET_PRIVATE (sock);
-
-	shutdown (priv->sockfd, SHUT_RDWR);
-}
-
 /**
  * soup_socket_connect_sync:
  * @sock: a client #SoupSocket (which must not already be connected)
@@ -770,7 +700,6 @@ guint
 soup_socket_connect_sync (SoupSocket *sock, GCancellable *cancellable)
 {
 	SoupSocketPrivate *priv;
-	guint status, cancel_id;
 
 	g_return_val_if_fail (SOUP_IS_SOCKET (sock), SOUP_STATUS_MALFORMED);
 	priv = SOUP_SOCKET_GET_PRIVATE (sock);
@@ -785,39 +714,24 @@ soup_socket_connect_sync (SoupSocket *sock, GCancellable *cancellable)
 			return status;
 	}
 
-	if (cancellable) {
-		cancel_id = g_signal_connect (cancellable, "cancelled",
-					      G_CALLBACK (sync_cancel), sock);
-	}
-
-	status = socket_connect_internal (sock);
-
-	if (cancellable) {
-		if (status != SOUP_STATUS_OK &&
-		    g_cancellable_is_cancelled (cancellable)) {
-			status = SOUP_STATUS_CANCELLED;
-			disconnect_internal (priv);
-		}
-		g_signal_handler_disconnect (cancellable, cancel_id);
-	}
-
-	return status;
+	return socket_connect_internal (sock, cancellable);
 }
 
 static gboolean
-listen_watch (GIOChannel* iochannel, GIOCondition condition, gpointer data)
+listen_watch (GSocket *gsock, GIOCondition condition, gpointer data)
 {
 	SoupSocket *sock = data, *new;
 	SoupSocketPrivate *priv = SOUP_SOCKET_GET_PRIVATE (sock), *new_priv;
-	struct soup_sockaddr_max sa;
+	struct sockaddr_storage sa;
 	int sa_len, sockfd;
 
 	if (condition & (G_IO_HUP | G_IO_ERR)) {
-		g_source_destroy (priv->watch_src);
 		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))
@@ -863,8 +777,7 @@ soup_socket_listen (SoupSocket *sock)
 
 {
 	SoupSocketPrivate *priv;
-	struct sockaddr *sa;
-	int sa_len;
+	GSocketAddress *addr;
 
 	g_return_val_if_fail (SOUP_IS_SOCKET (sock), FALSE);
 	priv = SOUP_SOCKET_GET_PRIVATE (sock);
@@ -879,33 +792,34 @@ soup_socket_listen (SoupSocket *sock)
 	 * have to make a new addr by calling getsockname(), which
 	 * will have the right port number.
 	 */
-	sa = soup_address_get_sockaddr (priv->local_addr, &sa_len);
-	g_return_val_if_fail (sa != NULL, FALSE);
+	addr = soup_address_get_gsockaddr (priv->local_addr);
+	g_return_val_if_fail (addr != NULL, FALSE);
 
-	priv->sockfd = socket (sa->sa_family, SOCK_STREAM, 0);
+	priv->sockfd = socket (soup_address_get_family (priv->local_addr),
+			       SOCK_STREAM, 0);
 	if (SOUP_IS_INVALID_SOCKET (priv->sockfd))
 		goto cant_listen;
 	set_fdflags (priv);
 
 	/* Bind */
-	if (bind (priv->sockfd, 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 | G_IO_ERR | G_IO_HUP,
+						    listen_watch, sock,
+						    NULL);
 	return TRUE;
 
  cant_listen:
-	if (priv->iochannel)
+	if (priv->gsock)
 		disconnect_internal (priv);
 
 	return FALSE;
@@ -1048,7 +962,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->gsock != NULL;
 }
 
 /**
@@ -1069,7 +983,7 @@ soup_socket_get_local_address (SoupSocket *sock)
 
 	g_mutex_lock (priv->addrlock);
 	if (!priv->local_addr) {
-		struct soup_sockaddr_max bound_sa;
+		struct sockaddr_storage bound_sa;
 		int sa_len;
 
 		sa_len = sizeof (bound_sa);
@@ -1099,7 +1013,7 @@ soup_socket_get_remote_address (SoupSocket *sock)
 
 	g_mutex_lock (priv->addrlock);
 	if (!priv->remote_addr) {
-		struct soup_sockaddr_max bound_sa;
+		struct sockaddr_storage bound_sa;
 		int sa_len;
 
 		sa_len = sizeof (bound_sa);
@@ -1137,7 +1051,7 @@ socket_timeout (gpointer sock)
 }
 
 static gboolean
-socket_read_watch (GIOChannel *chan, GIOCondition cond, gpointer user_data)
+socket_read_watch (GSocket *gsock, GIOCondition cond, gpointer user_data)
 {
 	SoupSocket *sock = user_data;
 	SoupSocketPrivate *priv = SOUP_SOCKET_GET_PRIVATE (sock);
@@ -1158,7 +1072,7 @@ socket_read_watch (GIOChannel *chan, GIOCondition cond, gpointer user_data)
 
 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;
@@ -1167,14 +1081,31 @@ read_from_network (SoupSocket *sock, gpointer buffer, gsize len,
 
 	*nread = 0;
 
-	if (!priv->iochannel)
+	if (!priv->gsock)
 		return SOUP_SOCKET_EOF;
 
 	if (priv->timed_out)
 		return SOUP_SOCKET_ERROR;
 
-	status = g_io_channel_read_chars (priv->iochannel,
-					  buffer, len, nread, &my_err);
+	while (1) {
+		if (!priv->non_blocking) {
+			if (!g_socket_condition_wait (priv->gsock, G_IO_IN,
+						      cancellable, &my_err))
+				break;
+		}
+
+		my_nread = g_socket_receive (priv->gsock, buffer, len, &my_err);
+
+		if (my_err->domain == G_IO_ERROR &&
+		    my_err->code == G_IO_ERROR_PENDING) {
+			g_error_free (my_err);
+			if (priv->non_blocking)
+				return SOUP_SOCKET_WOULD_BLOCK;
+			else
+				continue;
+		}
+	}
+
 	if (my_err) {
 		if (my_err->domain == SOUP_SSL_ERROR &&
 		    my_err->code == SOUP_SSL_ERROR_HANDSHAKE_NEEDS_WRITE)
diff --git a/libsoup/soup-ssl.h b/libsoup/soup-ssl.h
index f4e3eab..c3037e9 100644
--- a/libsoup/soup-ssl.h
+++ b/libsoup/soup-ssl.h
@@ -14,6 +14,7 @@ typedef enum {
 } SoupSSLType;
 
 typedef struct SoupSSLCredentials SoupSSLCredentials;
+typedef struct SoupSSLSession     SoupSSLSession;
 
 SoupSSLCredentials *soup_ssl_get_client_credentials  (const char         *ca_file);
 void                soup_ssl_free_client_credentials (SoupSSLCredentials *creds);
@@ -22,10 +23,20 @@ SoupSSLCredentials *soup_ssl_get_server_credentials  (const char         *cert_f
 						      const char         *key_file);
 void                soup_ssl_free_server_credentials (SoupSSLCredentials *creds);
 
-GIOChannel         *soup_ssl_wrap_iochannel          (GIOChannel         *sock,
-						      gboolean            non_blocking,
+SoupSSLSession     *soup_ssl_session_new             (GSocket            *gsock,
 						      SoupSSLType         type,
 						      const char         *remote_host,
 						      SoupSSLCredentials *creds);
 
+gssize              soup_ssl_session_receive         (SoupSSLSession     *session,
+						      gchar              *buffer,
+						      gsize               size,
+						      GCancellable       *cancellable,
+						      GError            **error);
+gssize              soup_ssl_session_send            (SoupSSLSession     *session,
+						      const gchar        *buffer,
+						      gsize               size,
+						      GCancellable       *cancellable,
+						      GError            **error);
+
 #endif /* SOUP_SSL_H */



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]