Index: lib/ssluse.c =================================================================== RCS file: /cvsroot/curl/curl/lib/ssluse.c,v retrieving revision 1.142 diff -u -r1.142 ssluse.c --- lib/ssluse.c 13 Mar 2006 23:34:25 -0000 1.142 +++ lib/ssluse.c 14 Mar 2006 11:56:16 -0000 @@ -1116,20 +1116,16 @@ #ifdef USE_SSLEAY /* ====================================================== */ -CURLcode -Curl_ossl_connect(struct connectdata *conn, + +static CURLcode +Curl_ossl_connect_step1(struct connectdata *conn, int sockindex) { CURLcode retcode = CURLE_OK; struct SessionHandle *data = conn->data; - int err; - long lerr; - int what; - char * str; SSL_METHOD_QUAL SSL_METHOD *req_method=NULL; void *ssl_sessionid=NULL; - ASN1_TIME *certdate; curl_socket_t sockfd = conn->sock[sockindex]; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; @@ -1296,135 +1292,144 @@ ERR_error_string(ERR_get_error(),NULL)); return CURLE_SSL_CONNECT_ERROR; } + + return CURLE_OK; +} - while(1) { - int writefd; - int readfd; - long timeout_ms; - long has_passed; - - /* Find out if any timeout is set. If not, use 300 seconds. - Otherwise, figure out the most strict timeout of the two possible one - and then how much time that has elapsed to know how much time we - allow for the connect call */ - if(data->set.timeout || data->set.connecttimeout) { - - /* get the most strict timeout of the ones converted to milliseconds */ - if(data->set.timeout && - (data->set.timeout>data->set.connecttimeout)) - timeout_ms = data->set.timeout*1000; - else - timeout_ms = data->set.connecttimeout*1000; - } +static CURLcode +Curl_ossl_connect_step2(struct connectdata *conn, + int sockindex, long* timeout_ms) +{ + struct SessionHandle *data = conn->data; + int err; + long has_passed; + struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + + + /* Find out if any timeout is set. If not, use 300 seconds. + Otherwise, figure out the most strict timeout of the two possible one + and then how much time that has elapsed to know how much time we + allow for the connect call */ + if(data->set.timeout || data->set.connecttimeout) { + + /* get the most strict timeout of the ones converted to milliseconds */ + if(data->set.timeout && + (data->set.timeout>data->set.connecttimeout)) + *timeout_ms = data->set.timeout*1000; else - /* no particular time-out has been set */ - timeout_ms= DEFAULT_CONNECT_TIMEOUT; + *timeout_ms = data->set.connecttimeout*1000; + } + else + /* no particular time-out has been set */ + *timeout_ms= DEFAULT_CONNECT_TIMEOUT; - /* Evaluate in milliseconds how much time that has passed */ - has_passed = Curl_tvdiff(Curl_tvnow(), data->progress.t_startsingle); + /* Evaluate in milliseconds how much time that has passed */ + has_passed = Curl_tvdiff(Curl_tvnow(), data->progress.t_startsingle); - /* subtract the passed time */ - timeout_ms -= has_passed; + /* subtract the passed time */ + *timeout_ms -= has_passed; - if(timeout_ms < 0) { - /* a precaution, no need to continue if time already is up */ - failf(data, "SSL connection timeout"); - return CURLE_OPERATION_TIMEOUTED; - } + if(*timeout_ms < 0) { + /* a precaution, no need to continue if time already is up */ + failf(data, "SSL connection timeout"); + return CURLE_OPERATION_TIMEOUTED; + } - readfd = CURL_SOCKET_BAD; - writefd = CURL_SOCKET_BAD; + err = SSL_connect(connssl->handle); - err = SSL_connect(connssl->handle); + /* 1 is fine + 0 is "not successful but was shut down controlled" + <0 is "handshake was not successful, because a fatal error occurred" */ + if(1 != err) { + int detail = SSL_get_error(connssl->handle, err); - /* 1 is fine - 0 is "not successful but was shut down controlled" - <0 is "handshake was not successful, because a fatal error occurred" */ - if(1 != err) { - int detail = SSL_get_error(connssl->handle, err); + if(SSL_ERROR_WANT_READ == detail) { + connssl->connect_pending_readwrite = 1; + return CURLE_OK; + } + else if(SSL_ERROR_WANT_WRITE == detail) { + connssl->connect_pending_readwrite = 2; + return CURLE_OK; + } + else { + /* untreated error */ + unsigned long errdetail; + char error_buffer[120]; /* OpenSSL documents that this must be at least + 120 bytes long. */ + CURLcode rc; + const char *cert_problem = NULL; - if(SSL_ERROR_WANT_READ == detail) - readfd = sockfd; - else if(SSL_ERROR_WANT_WRITE == detail) - writefd = sockfd; - else { - /* untreated error */ - unsigned long errdetail; - char error_buffer[120]; /* OpenSSL documents that this must be at least - 120 bytes long. */ - CURLcode rc; - const char *cert_problem = NULL; + connssl->connect_pending_readwrite = 0; /* the connection failed, + we're not waiting for anything else. */ - errdetail = ERR_get_error(); /* Gets the earliest error code from the + errdetail = ERR_get_error(); /* Gets the earliest error code from the thread's error queue and removes the entry. */ - switch(errdetail) { - case 0x1407E086: - /* 1407E086: - SSL routines: - SSL2_SET_CERTIFICATE: - certificate verify failed */ - /* fall-through */ - case 0x14090086: - /* 14090086: - SSL routines: - SSL3_GET_SERVER_CERTIFICATE: - certificate verify failed */ - cert_problem = "SSL certificate problem, verify that the CA cert is" - " OK. Details:\n"; - rc = CURLE_SSL_CACERT; - break; - default: - rc = CURLE_SSL_CONNECT_ERROR; - break; - } - - /* detail is already set to the SSL error above */ + switch(errdetail) { + case 0x1407E086: + /* 1407E086: + SSL routines: + SSL2_SET_CERTIFICATE: + certificate verify failed */ + /* fall-through */ + case 0x14090086: + /* 14090086: + SSL routines: + SSL3_GET_SERVER_CERTIFICATE: + certificate verify failed */ + cert_problem = "SSL certificate problem, verify that the CA cert is" + " OK. Details:\n"; + rc = CURLE_SSL_CACERT; + break; + default: + rc = CURLE_SSL_CONNECT_ERROR; + break; + } - /* If we e.g. use SSLv2 request-method and the server doesn't like us - * (RST connection etc.), OpenSSL gives no explanation whatsoever and - * the SO_ERROR is also lost. - */ - if (CURLE_SSL_CONNECT_ERROR == rc && errdetail == 0) { - failf(data, "Unknown SSL protocol error in connection to %s:%d ", - conn->host.name, conn->port); - return rc; - } - /* Could be a CERT problem */ + /* detail is already set to the SSL error above */ - SSL_strerror(errdetail, error_buffer, sizeof(error_buffer)); - failf(data, "%s%s", cert_problem ? cert_problem : "", error_buffer); + /* If we e.g. use SSLv2 request-method and the server doesn't like us + * (RST connection etc.), OpenSSL gives no explanation whatsoever and + * the SO_ERROR is also lost. + */ + if (CURLE_SSL_CONNECT_ERROR == rc && errdetail == 0) { + failf(data, "Unknown SSL protocol error in connection to %s:%d ", + conn->host.name, conn->port); return rc; } + /* Could be a CERT problem */ + + SSL_strerror(errdetail, error_buffer, sizeof(error_buffer)); + failf(data, "%s%s", cert_problem ? cert_problem : "", error_buffer); + return rc; } - else - /* we have been connected fine, get out of the connect loop */ - break; + } + else { + /* we have been connected fine, we're not waiting for anything else. */ + connssl->connect_pending_readwrite = 0; + + /* Informational message */ + infof (data, "SSL connection using %s\n", + SSL_get_cipher(connssl->handle)); - while(1) { - what = Curl_select(readfd, writefd, (int)timeout_ms); - if(what > 0) - /* reabable or writable, go loop in the outer loop */ - break; - else if(0 == what) { - /* timeout */ - failf(data, "SSL connection timeout"); - return CURLE_OPERATION_TIMEDOUT; - } - else { - /* anything that gets here is fatally bad */ - failf(data, "select on SSL socket, errno: %d", Curl_ourerrno()); - return CURLE_SSL_CONNECT_ERROR; - } - } /* while()-loop for the select() */ - } /* while()-loop for the SSL_connect() */ + return CURLE_OK; + } +} - /* Informational message */ - infof (data, "SSL connection using %s\n", - SSL_get_cipher(connssl->handle)); +static CURLcode +Curl_ossl_connect_step3(struct connectdata *conn, + int sockindex) +{ + CURLcode retcode = CURLE_OK; + char * str; + long lerr; + ASN1_TIME *certdate; + void *ssl_sessionid=NULL; + struct SessionHandle *data = conn->data; + struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - if(!ssl_sessionid) { + if(Curl_ssl_getsessionid(conn, &ssl_sessionid, NULL)) { /* Since this is not a cached session ID, then we want to stach this one in the cache! */ SSL_SESSION *ssl_sessionid; @@ -1532,6 +1537,59 @@ return retcode; } +CURLcode +Curl_ossl_connect(struct connectdata *conn, + int sockindex) +{ + CURLcode retcode; + struct SessionHandle *data = conn->data; + struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + curl_socket_t sockfd = conn->sock[sockindex]; + + retcode = Curl_ossl_connect_step1(conn, sockindex); + if (retcode) + return retcode; + + do { + long timeout_ms; /* avoid computing the timeout twice. */ + retcode = Curl_ossl_connect_step2(conn, sockindex, &timeout_ms); + if (retcode) + return retcode; + + /* is ssl expecting something? */ + if (connssl->connect_pending_readwrite) { + int writefd = (connssl->connect_pending_readwrite&2) ? sockfd : CURL_SOCKET_BAD; + int readfd = (connssl->connect_pending_readwrite&1) ? sockfd : CURL_SOCKET_BAD; + while(1) { + int what = Curl_select(readfd, writefd, (int)timeout_ms); + if(what > 0) + /* reabable or writable, go loop in the outer loop */ + break; + else if(0 == what) { + /* timeout */ + failf(data, "SSL connection timeout"); + return CURLE_OPERATION_TIMEDOUT; + } + else { + /* anything that gets here is fatally bad */ + failf(data, "select on SSL socket, errno: %d", Curl_ourerrno()); + return CURLE_SSL_CONNECT_ERROR; + } + } /* while()-loop for the select() */ + } + + /* repeat step2 until all transactions are done. */ + } while (connssl->connect_pending_readwrite); + + retcode = Curl_ossl_connect_step3(conn, sockindex); + if (retcode) + return retcode; + + return CURLE_OK; +} + + + /* return number of sent (non-SSL) bytes */ int Curl_ossl_send(struct connectdata *conn, int sockindex, Index: lib/urldata.h =================================================================== RCS file: /cvsroot/curl/curl/lib/urldata.h,v retrieving revision 1.281 diff -u -r1.281 urldata.h --- lib/urldata.h 7 Mar 2006 23:11:42 -0000 1.281 +++ lib/urldata.h 14 Mar 2006 11:56:17 -0000 @@ -143,6 +143,7 @@ SSL_CTX* ctx; SSL* handle; X509* server_cert; + int connect_pending_readwrite; /* 0: not waiting, 1: reading, 2: writing */ #endif /* USE_SSLEAY */ #ifdef USE_GNUTLS gnutls_session session;