File libsoup-2.2.96-blocking-eagain.patch of Package libsoup

--- trunk/libsoup/soup-gnutls.c	2006/11/20 21:47:04	900
+++ trunk/libsoup/soup-gnutls.c	2007/03/08 21:11:00	914
@@ -2,10 +2,7 @@
 /*
  * soup-gnutls.c
  *
- * Authors:
- *      Ian Peters <itp@ximian.com>
- *
- * Copyright (C) 2003, Ximian, Inc.
+ * Copyright (C) 2003-2006, Novell, Inc.
  */
 
 #ifdef HAVE_CONFIG_H
@@ -15,6 +12,7 @@
 #ifdef HAVE_SSL
 
 #include <errno.h>
+#include <fcntl.h>
 #include <pthread.h>
 #include <stdlib.h>
 #include <string.h>
@@ -129,21 +127,26 @@
 	return TRUE;
 }
 
+#define SOUP_GNUTLS_CHANNEL_NONBLOCKING(chan) (fcntl ((chan)->fd, F_GETFL, 0) & O_NONBLOCK)
+
 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) {
-		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;
+	if (result == GNUTLS_E_AGAIN || result == GNUTLS_E_INTERRUPTED) {
+		if (SOUP_GNUTLS_CHANNEL_NONBLOCKING (chan)) {
+			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) {
@@ -172,6 +175,7 @@
 
 	*bytes_read = 0;
 
+again:
 	if (!chan->established) {
 		result = do_handshake (chan, err);
 
@@ -186,13 +190,17 @@
 
 	if (result == GNUTLS_E_REHANDSHAKE) {
 		chan->established = FALSE;
-		return G_IO_STATUS_AGAIN;
+		goto again;
 	}
 
-	if (result < 0) {
-		if ((result == GNUTLS_E_INTERRUPTED) ||
-		    (result == GNUTLS_E_AGAIN))
+	if (result == GNUTLS_E_INTERRUPTED || result == GNUTLS_E_AGAIN) {
+		if (SOUP_GNUTLS_CHANNEL_NONBLOCKING (chan))
 			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");
@@ -216,6 +224,7 @@
 
 	*bytes_written = 0;
 
+again:
 	if (!chan->established) {
 		result = do_handshake (chan, err);
 
@@ -228,15 +237,22 @@
 
 	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;
-		return G_IO_STATUS_AGAIN;
+		goto again;
 	}
 
-	if (result < 0) {
-		if ((result == GNUTLS_E_INTERRUPTED) ||
-		    (result == GNUTLS_E_AGAIN))
+	if (result == GNUTLS_E_INTERRUPTED || result == GNUTLS_E_AGAIN) {
+		if (SOUP_GNUTLS_CHANNEL_NONBLOCKING (chan))
 			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");
openSUSE Build Service is sponsored by