darwinssl: fixed freeze involving the multi interface

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.
This commit is contained in:
Nick Zitzmann 2012-07-16 20:20:57 -06:00 committed by Daniel Stenberg
parent 9ac5cdfc2f
commit f92779198d
3 changed files with 25 additions and 24 deletions

View File

@ -71,7 +71,9 @@ static OSStatus SocketRead(SSLConnectionRef connection,
UInt32 bytesToGo = *dataLength; UInt32 bytesToGo = *dataLength;
UInt32 initLen = bytesToGo; UInt32 initLen = bytesToGo;
UInt8 *currData = (UInt8 *)data; 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; OSStatus rtn = noErr;
UInt32 bytesRead; UInt32 bytesRead;
int rrtn; int rrtn;
@ -100,6 +102,7 @@ static OSStatus SocketRead(SSLConnectionRef connection,
break; break;
case EAGAIN: case EAGAIN:
rtn = errSSLWouldBlock; rtn = errSSLWouldBlock;
connssl->ssl_direction = false;
break; break;
default: default:
rtn = ioErr; rtn = ioErr;
@ -128,7 +131,9 @@ static OSStatus SocketWrite(SSLConnectionRef connection,
size_t *dataLength) /* IN/OUT */ size_t *dataLength) /* IN/OUT */
{ {
UInt32 bytesSent = 0; 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; int length;
UInt32 dataLen = *dataLength; UInt32 dataLen = *dataLength;
const UInt8 *dataPtr = (UInt8 *)data; const UInt8 *dataPtr = (UInt8 *)data;
@ -148,6 +153,7 @@ static OSStatus SocketWrite(SSLConnectionRef connection,
theErr = errno; theErr = errno;
if(theErr == EAGAIN) { if(theErr == EAGAIN) {
ortn = errSSLWouldBlock; ortn = errSSLWouldBlock;
connssl->ssl_direction = true;
} }
else { else {
ortn = ioErr; ortn = ioErr;
@ -388,7 +394,7 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn,
#else #else
struct in_addr addr; struct in_addr addr;
#endif #endif
SSLConnectionRef ssl_connection; /*SSLConnectionRef ssl_connection;*/
OSStatus err = noErr; OSStatus err = noErr;
if(connssl->ssl_ctx) 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 * SSLSetConnection() will not copy that address. I've found that
* conn->sock[sockindex] may change on its own. */ * conn->sock[sockindex] may change on its own. */
connssl->ssl_sockfd = sockfd; connssl->ssl_sockfd = sockfd;
ssl_connection = &(connssl->ssl_sockfd); /*ssl_connection = &(connssl->ssl_sockfd);
err = SSLSetConnection(connssl->ssl_ctx, ssl_connection); err = SSLSetConnection(connssl->ssl_ctx, ssl_connection);*/
err = SSLSetConnection(connssl->ssl_ctx, connssl);
if(err != noErr) { if(err != noErr) {
failf(data, "SSL: SSLSetConnection() failed: %d", err); failf(data, "SSL: SSLSetConnection() failed: %d", err);
return CURLE_SSL_CONNECT_ERROR; return CURLE_SSL_CONNECT_ERROR;
@ -488,8 +495,7 @@ darwinssl_connect_step2(struct connectdata *conn, int sockindex)
DEBUGASSERT(ssl_connect_2 == connssl->connecting_state DEBUGASSERT(ssl_connect_2 == connssl->connecting_state
|| ssl_connect_2_reading == connssl->connecting_state || ssl_connect_2_reading == connssl->connecting_state
|| ssl_connect_2_writing == connssl->connecting_state || ssl_connect_2_writing == connssl->connecting_state);
|| ssl_connect_2_wouldblock == connssl->connecting_state);
/* Here goes nothing: */ /* Here goes nothing: */
err = SSLHandshake(connssl->ssl_ctx); err = SSLHandshake(connssl->ssl_ctx);
@ -497,7 +503,8 @@ darwinssl_connect_step2(struct connectdata *conn, int sockindex)
if(err != noErr) { if(err != noErr) {
switch (err) { switch (err) {
case errSSLWouldBlock: /* they're not done with us yet */ 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; return CURLE_OK;
break; break;
@ -609,8 +616,7 @@ darwinssl_connect_common(struct connectdata *conn,
while(ssl_connect_2 == connssl->connecting_state || while(ssl_connect_2 == connssl->connecting_state ||
ssl_connect_2_reading == connssl->connecting_state || ssl_connect_2_reading == connssl->connecting_state ||
ssl_connect_2_writing == connssl->connecting_state || ssl_connect_2_writing == connssl->connecting_state) {
ssl_connect_2_wouldblock == connssl->connecting_state) {
/* check allowed time left */ /* check allowed time left */
timeout_ms = Curl_timeleft(data, NULL, TRUE); 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 ssl is expecting something, check if it's available. */
if(connssl->connecting_state == ssl_connect_2_reading if(connssl->connecting_state == ssl_connect_2_reading
|| connssl->connecting_state == ssl_connect_2_writing || connssl->connecting_state == ssl_connect_2_writing) {
|| connssl->connecting_state == ssl_connect_2_wouldblock) {
curl_socket_t writefd = ssl_connect_2_writing curl_socket_t writefd = ssl_connect_2_writing ==
|| ssl_connect_2_wouldblock ==
connssl->connecting_state?sockfd:CURL_SOCKET_BAD; connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
curl_socket_t readfd = ssl_connect_2_reading curl_socket_t readfd = ssl_connect_2_reading ==
|| ssl_connect_2_wouldblock ==
connssl->connecting_state?sockfd:CURL_SOCKET_BAD; connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
what = Curl_socket_ready(readfd, writefd, nonblocking?0:timeout_ms); what = Curl_socket_ready(readfd, writefd, nonblocking?0:timeout_ms);
@ -663,8 +666,7 @@ darwinssl_connect_common(struct connectdata *conn,
if(retcode || (nonblocking && if(retcode || (nonblocking &&
(ssl_connect_2 == connssl->connecting_state || (ssl_connect_2 == connssl->connecting_state ||
ssl_connect_2_reading == connssl->connecting_state || ssl_connect_2_reading == connssl->connecting_state ||
ssl_connect_2_writing == connssl->connecting_state || ssl_connect_2_writing == connssl->connecting_state)))
ssl_connect_2_wouldblock == connssl->connecting_state)))
return retcode; return retcode;
} /* repeat step2 until all transactions are done. */ } /* repeat step2 until all transactions are done. */

View File

@ -1371,9 +1371,10 @@ static CURLcode https_connecting(struct connectdata *conn, bool *done)
} }
#endif #endif
#if defined(USE_SSLEAY) || defined(USE_GNUTLS) || defined(USE_SCHANNEL) #if defined(USE_SSLEAY) || defined(USE_GNUTLS) || defined(USE_SCHANNEL) || \
/* This function is for OpenSSL, GnuTLS and schannel only. It should be defined(USE_DARWINSSL)
made to query the generic SSL layer instead. */ /* 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, static int https_getsock(struct connectdata *conn,
curl_socket_t *socks, curl_socket_t *socks,
int numsocks) int numsocks)

View File

@ -248,9 +248,6 @@ typedef enum {
ssl_connect_2, ssl_connect_2,
ssl_connect_2_reading, ssl_connect_2_reading,
ssl_connect_2_writing, ssl_connect_2_writing,
#ifdef USE_DARWINSSL
ssl_connect_2_wouldblock,
#endif /* USE_DARWINSSL */
ssl_connect_3, ssl_connect_3,
ssl_connect_done ssl_connect_done
} ssl_connect_state; } ssl_connect_state;
@ -327,6 +324,7 @@ struct ssl_connect_data {
SSLContextRef ssl_ctx; SSLContextRef ssl_ctx;
curl_socket_t ssl_sockfd; curl_socket_t ssl_sockfd;
ssl_connect_state connecting_state; ssl_connect_state connecting_state;
bool ssl_direction; /* true if writing, false if reading */
#endif /* USE_DARWINSSL */ #endif /* USE_DARWINSSL */
}; };