From 8d793e089c59d325a3b0987d4b8cfdc7e1bf50e5 Mon Sep 17 00:00:00 2001
From: Nick Zitzmann <nick@chronosnet.com>
Date: Mon, 16 Jul 2012 20:20:57 -0600
Subject: [PATCH 2/2] Fixed freeze involving the multi interface and darwinssl

Previously the curl_multi interface would freeze if darwinssl was enabled and at least one of the handles tried to connect to a Web site using HTTPS. Removed the "wouldblock" state darwinssl was using because I figured out a solution for our "would block but in which direction?" dilemma.
---
 lib/curl_darwinssl.c |   38 ++++++++++++++++++++------------------
 lib/http.c           |    7 ++++---
 lib/urldata.h        |    4 +---
 3 files changed, 25 insertions(+), 24 deletions(-)

diff --git a/lib/curl_darwinssl.c b/lib/curl_darwinssl.c
index 893a6fc..c848be7 100644
--- a/lib/curl_darwinssl.c
+++ b/lib/curl_darwinssl.c
@@ -71,7 +71,9 @@ static OSStatus SocketRead(SSLConnectionRef connection,
   UInt32 bytesToGo = *dataLength;
   UInt32 initLen = bytesToGo;
   UInt8 *currData = (UInt8 *)data;
-  int sock = *(int *)connection;
+  /*int sock = *(int *)connection;*/
+  struct ssl_connect_data *connssl = (struct ssl_connect_data *)connection;
+  int sock = connssl->ssl_sockfd;
   OSStatus rtn = noErr;
   UInt32 bytesRead;
   int rrtn;
@@ -100,6 +102,7 @@ static OSStatus SocketRead(SSLConnectionRef connection,
             break;
           case EAGAIN:
             rtn = errSSLWouldBlock;
+            connssl->ssl_direction = false;
             break;
           default:
             rtn = ioErr;
@@ -128,7 +131,9 @@ static OSStatus SocketWrite(SSLConnectionRef connection,
                             size_t *dataLength)  /* IN/OUT */
 {
   UInt32 bytesSent = 0;
-  int sock = *(int *)connection;
+  /*int sock = *(int *)connection;*/
+  struct ssl_connect_data *connssl = (struct ssl_connect_data *)connection;
+  int sock = connssl->ssl_sockfd;
   int length;
   UInt32 dataLen = *dataLength;
   const UInt8 *dataPtr = (UInt8 *)data;
@@ -148,6 +153,7 @@ static OSStatus SocketWrite(SSLConnectionRef connection,
     theErr = errno;
     if(theErr == EAGAIN) {
       ortn = errSSLWouldBlock;
+      connssl->ssl_direction = true;
     }
     else {
       ortn = ioErr;
@@ -388,7 +394,7 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn,
 #else
   struct in_addr addr;
 #endif
-  SSLConnectionRef ssl_connection;
+  /*SSLConnectionRef ssl_connection;*/
   OSStatus err = noErr;
 
   if(connssl->ssl_ctx)
@@ -467,8 +473,9 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn,
    * SSLSetConnection() will not copy that address. I've found that
    * conn->sock[sockindex] may change on its own. */
   connssl->ssl_sockfd = sockfd;
-  ssl_connection = &(connssl->ssl_sockfd);
-  err = SSLSetConnection(connssl->ssl_ctx, ssl_connection);
+  /*ssl_connection = &(connssl->ssl_sockfd);
+  err = SSLSetConnection(connssl->ssl_ctx, ssl_connection);*/
+  err = SSLSetConnection(connssl->ssl_ctx, connssl);
   if(err != noErr) {
     failf(data, "SSL: SSLSetConnection() failed: %d", err);
     return CURLE_SSL_CONNECT_ERROR;
@@ -488,8 +495,7 @@ darwinssl_connect_step2(struct connectdata *conn, int sockindex)
 
   DEBUGASSERT(ssl_connect_2 == connssl->connecting_state
               || ssl_connect_2_reading == connssl->connecting_state
-              || ssl_connect_2_writing == connssl->connecting_state
-              || ssl_connect_2_wouldblock == connssl->connecting_state);
+              || ssl_connect_2_writing == connssl->connecting_state);
 
   /* Here goes nothing: */
   err = SSLHandshake(connssl->ssl_ctx);
@@ -497,7 +503,8 @@ darwinssl_connect_step2(struct connectdata *conn, int sockindex)
   if(err != noErr) {
     switch (err) {
       case errSSLWouldBlock:  /* they're not done with us yet */
-        connssl->connecting_state = ssl_connect_2_wouldblock;
+        connssl->connecting_state = connssl->ssl_direction ?
+            ssl_connect_2_writing : ssl_connect_2_reading;
         return CURLE_OK;
         break;
 
@@ -609,8 +616,7 @@ darwinssl_connect_common(struct connectdata *conn,
 
   while(ssl_connect_2 == connssl->connecting_state ||
         ssl_connect_2_reading == connssl->connecting_state ||
-        ssl_connect_2_writing == connssl->connecting_state ||
-        ssl_connect_2_wouldblock == connssl->connecting_state) {
+        ssl_connect_2_writing == connssl->connecting_state) {
 
     /* check allowed time left */
     timeout_ms = Curl_timeleft(data, NULL, TRUE);
@@ -623,14 +629,11 @@ darwinssl_connect_common(struct connectdata *conn,
 
     /* if ssl is expecting something, check if it's available. */
     if(connssl->connecting_state == ssl_connect_2_reading
-       || connssl->connecting_state == ssl_connect_2_writing
-       || connssl->connecting_state == ssl_connect_2_wouldblock) {
+       || connssl->connecting_state == ssl_connect_2_writing) {
 
-      curl_socket_t writefd = ssl_connect_2_writing
-      || ssl_connect_2_wouldblock ==
+      curl_socket_t writefd = ssl_connect_2_writing ==
       connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
-      curl_socket_t readfd = ssl_connect_2_reading
-      || ssl_connect_2_wouldblock ==
+      curl_socket_t readfd = ssl_connect_2_reading ==
       connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
 
       what = Curl_socket_ready(readfd, writefd, nonblocking?0:timeout_ms);
@@ -663,8 +666,7 @@ darwinssl_connect_common(struct connectdata *conn,
     if(retcode || (nonblocking &&
                    (ssl_connect_2 == connssl->connecting_state ||
                     ssl_connect_2_reading == connssl->connecting_state ||
-                    ssl_connect_2_writing == connssl->connecting_state ||
-                    ssl_connect_2_wouldblock == connssl->connecting_state)))
+                    ssl_connect_2_writing == connssl->connecting_state)))
       return retcode;
 
   } /* repeat step2 until all transactions are done. */
diff --git a/lib/http.c b/lib/http.c
index b421a2c..2e021b1 100644
--- a/lib/http.c
+++ b/lib/http.c
@@ -1371,9 +1371,10 @@ static CURLcode https_connecting(struct connectdata *conn, bool *done)
 }
 #endif
 
-#if defined(USE_SSLEAY) || defined(USE_GNUTLS) || defined(USE_SCHANNEL)
-/* This function is for OpenSSL, GnuTLS and schannel only. It should be
-   made to query the generic SSL layer instead. */
+#if defined(USE_SSLEAY) || defined(USE_GNUTLS) || defined(USE_SCHANNEL) || \
+    defined(USE_DARWINSSL)
+/* This function is for OpenSSL, GnuTLS, darwinssl, and schannel only.
+   It should be made to query the generic SSL layer instead. */
 static int https_getsock(struct connectdata *conn,
                          curl_socket_t *socks,
                          int numsocks)
diff --git a/lib/urldata.h b/lib/urldata.h
index 5ad07c5..fddfc0d 100644
--- a/lib/urldata.h
+++ b/lib/urldata.h
@@ -248,9 +248,6 @@ typedef enum {
   ssl_connect_2,
   ssl_connect_2_reading,
   ssl_connect_2_writing,
-#ifdef USE_DARWINSSL
-  ssl_connect_2_wouldblock,
-#endif /* USE_DARWINSSL */
   ssl_connect_3,
   ssl_connect_done
 } ssl_connect_state;
@@ -327,6 +324,7 @@ struct ssl_connect_data {
   SSLContextRef ssl_ctx;
   curl_socket_t ssl_sockfd;
   ssl_connect_state connecting_state;
+  bool ssl_direction; /* true if writing, false if reading */
 #endif /* USE_DARWINSSL */
 };
 
-- 
1.7.7.5 (Apple Git-26)


