Xavier Bouchoux made the SSL connection non-blocking for the multi interface
(when using OpenSSL).
This commit is contained in:
3
CHANGES
3
CHANGES
@@ -7,6 +7,9 @@
|
|||||||
Changelog
|
Changelog
|
||||||
|
|
||||||
Daniel (21 March 2006)
|
Daniel (21 March 2006)
|
||||||
|
- Xavier Bouchoux made the SSL connection non-blocking for the multi interface
|
||||||
|
(when using OpenSSL).
|
||||||
|
|
||||||
- Tor Arntsen fixed the AIX Toolbox RPM spec
|
- Tor Arntsen fixed the AIX Toolbox RPM spec
|
||||||
|
|
||||||
Daniel (20 March 2006)
|
Daniel (20 March 2006)
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ Curl and libcurl 7.15.4
|
|||||||
|
|
||||||
This release includes the following changes:
|
This release includes the following changes:
|
||||||
|
|
||||||
o
|
o less blocking for the multi interface during SSL connect negotiation
|
||||||
|
|
||||||
This release includes the following bugfixes:
|
This release includes the following bugfixes:
|
||||||
|
|
||||||
@@ -27,6 +27,6 @@ Other curl-related news since the previous public release:
|
|||||||
This release would not have looked like this without help, code, reports and
|
This release would not have looked like this without help, code, reports and
|
||||||
advice from friends like these:
|
advice from friends like these:
|
||||||
|
|
||||||
Dan Fandrich, Ilja van Sprundel, David McCreedy, Tor Arntsen
|
Dan Fandrich, Ilja van Sprundel, David McCreedy, Tor Arntsen, Xavier Bouchoux
|
||||||
|
|
||||||
Thanks! (and sorry if I forgot to mention someone)
|
Thanks! (and sorry if I forgot to mention someone)
|
||||||
|
|||||||
66
lib/http.c
66
lib/http.c
@@ -1371,13 +1371,6 @@ CURLcode Curl_http_connect(struct connectdata *conn, bool *done)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(conn->protocol & PROT_HTTPS) {
|
|
||||||
/* perform SSL initialization for this socket */
|
|
||||||
result = Curl_ssl_connect(conn, FIRSTSOCKET);
|
|
||||||
if(result)
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!data->state.this_is_a_follow) {
|
if(!data->state.this_is_a_follow) {
|
||||||
/* this is not a followed location, get the original host name */
|
/* this is not a followed location, get the original host name */
|
||||||
if (data->state.first_host)
|
if (data->state.first_host)
|
||||||
@@ -1387,11 +1380,68 @@ CURLcode Curl_http_connect(struct connectdata *conn, bool *done)
|
|||||||
data->state.first_host = strdup(conn->host.name);
|
data->state.first_host = strdup(conn->host.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
*done = TRUE;
|
if(conn->protocol & PROT_HTTPS) {
|
||||||
|
/* perform SSL initialization */
|
||||||
|
if(data->state.used_interface == Curl_if_multi) {
|
||||||
|
result = Curl_https_connecting(conn, done);
|
||||||
|
if(result)
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* BLOCKING */
|
||||||
|
result = Curl_ssl_connect(conn, FIRSTSOCKET);
|
||||||
|
if(result)
|
||||||
|
return result;
|
||||||
|
*done = TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
*done = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
return CURLE_OK;
|
return CURLE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CURLcode Curl_https_connecting(struct connectdata *conn, bool *done)
|
||||||
|
{
|
||||||
|
CURLcode result;
|
||||||
|
curlassert(conn->protocol & PROT_HTTPS);
|
||||||
|
|
||||||
|
/* perform SSL initialization for this socket */
|
||||||
|
result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, done);
|
||||||
|
if(result)
|
||||||
|
return result;
|
||||||
|
|
||||||
|
return CURLE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef USE_SSLEAY
|
||||||
|
CURLcode Curl_https_proto_fdset(struct connectdata *conn,
|
||||||
|
fd_set *read_fd_set,
|
||||||
|
fd_set *write_fd_set,
|
||||||
|
int *max_fdp)
|
||||||
|
{
|
||||||
|
if (conn->protocol & PROT_HTTPS) {
|
||||||
|
struct ssl_connect_data *connssl = &conn->ssl[FIRSTSOCKET];
|
||||||
|
curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
|
||||||
|
|
||||||
|
if (connssl->connecting_state == ssl_connect_2_writing) {
|
||||||
|
/* write mode */
|
||||||
|
FD_SET(sockfd, write_fd_set);
|
||||||
|
if((int)sockfd > *max_fdp)
|
||||||
|
*max_fdp = (int)sockfd;
|
||||||
|
}
|
||||||
|
else if (connssl->connecting_state == ssl_connect_2_reading) {
|
||||||
|
/* read mode */
|
||||||
|
FD_SET(sockfd, read_fd_set);
|
||||||
|
if((int)sockfd > *max_fdp)
|
||||||
|
*max_fdp = (int)sockfd;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return CURLE_OK;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Curl_http_done() gets called from Curl_done() after a single HTTP request
|
* Curl_http_done() gets called from Curl_done() after a single HTTP request
|
||||||
* has been performed.
|
* has been performed.
|
||||||
|
|||||||
@@ -37,6 +37,11 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn,
|
|||||||
CURLcode Curl_http(struct connectdata *conn, bool *done);
|
CURLcode Curl_http(struct connectdata *conn, bool *done);
|
||||||
CURLcode Curl_http_done(struct connectdata *, CURLcode);
|
CURLcode Curl_http_done(struct connectdata *, CURLcode);
|
||||||
CURLcode Curl_http_connect(struct connectdata *conn, bool *done);
|
CURLcode Curl_http_connect(struct connectdata *conn, bool *done);
|
||||||
|
CURLcode Curl_https_connecting(struct connectdata *conn, bool *done);
|
||||||
|
CURLcode Curl_https_proto_fdset(struct connectdata *conn,
|
||||||
|
fd_set *read_fd_set,
|
||||||
|
fd_set *write_fd_set,
|
||||||
|
int *max_fdp);
|
||||||
|
|
||||||
/* The following functions are defined in http_chunks.c */
|
/* The following functions are defined in http_chunks.c */
|
||||||
void Curl_httpchunk_init(struct connectdata *conn);
|
void Curl_httpchunk_init(struct connectdata *conn);
|
||||||
|
|||||||
19
lib/sslgen.c
19
lib/sslgen.c
@@ -5,7 +5,7 @@
|
|||||||
* | (__| |_| | _ <| |___
|
* | (__| |_| | _ <| |___
|
||||||
* \___|\___/|_| \_\_____|
|
* \___|\___/|_| \_\_____|
|
||||||
*
|
*
|
||||||
* Copyright (C) 1998 - 2005, Daniel Stenberg, <daniel@haxx.se>, et al.
|
* Copyright (C) 1998 - 2006, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||||
*
|
*
|
||||||
* This software is licensed as described in the file COPYING, which
|
* This software is licensed as described in the file COPYING, which
|
||||||
* you should have received as part of this distribution. The terms
|
* you should have received as part of this distribution. The terms
|
||||||
@@ -215,6 +215,23 @@ Curl_ssl_connect(struct connectdata *conn, int sockindex)
|
|||||||
#endif /* USE_SSL */
|
#endif /* USE_SSL */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CURLcode
|
||||||
|
Curl_ssl_connect_nonblocking(struct connectdata *conn, int sockindex,
|
||||||
|
bool *done)
|
||||||
|
{
|
||||||
|
#if defined(USE_SSL) && defined(USE_SSLEAY)
|
||||||
|
/* mark this is being ssl enabled from here on. */
|
||||||
|
conn->ssl[sockindex].use = TRUE;
|
||||||
|
return Curl_ossl_connect_nonblocking(conn, sockindex, done);
|
||||||
|
|
||||||
|
#else
|
||||||
|
/* not implemented!
|
||||||
|
fallback to BLOCKING call. */
|
||||||
|
*done = TRUE;
|
||||||
|
return Curl_ssl_connect(conn, sockindex);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef USE_SSL
|
#ifdef USE_SSL
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -32,6 +32,9 @@ void Curl_free_ssl_config(struct ssl_config_data* sslc);
|
|||||||
int Curl_ssl_init(void);
|
int Curl_ssl_init(void);
|
||||||
void Curl_ssl_cleanup(void);
|
void Curl_ssl_cleanup(void);
|
||||||
CURLcode Curl_ssl_connect(struct connectdata *conn, int sockindex);
|
CURLcode Curl_ssl_connect(struct connectdata *conn, int sockindex);
|
||||||
|
CURLcode Curl_ssl_connect_nonblocking(struct connectdata *conn,
|
||||||
|
int sockindex,
|
||||||
|
bool *done);
|
||||||
void Curl_ssl_close(struct connectdata *conn);
|
void Curl_ssl_close(struct connectdata *conn);
|
||||||
/* tell the SSL stuff to close down all open information regarding
|
/* tell the SSL stuff to close down all open information regarding
|
||||||
connections (and thus session ID caching etc) */
|
connections (and thus session ID caching etc) */
|
||||||
|
|||||||
353
lib/ssluse.c
353
lib/ssluse.c
@@ -1116,23 +1116,21 @@ static void ssl_tls_trace(int direction, int ssl_ver, int content_type,
|
|||||||
|
|
||||||
#ifdef USE_SSLEAY
|
#ifdef USE_SSLEAY
|
||||||
/* ====================================================== */
|
/* ====================================================== */
|
||||||
CURLcode
|
|
||||||
Curl_ossl_connect(struct connectdata *conn,
|
static CURLcode
|
||||||
|
Curl_ossl_connect_step1(struct connectdata *conn,
|
||||||
int sockindex)
|
int sockindex)
|
||||||
{
|
{
|
||||||
CURLcode retcode = CURLE_OK;
|
CURLcode retcode = CURLE_OK;
|
||||||
|
|
||||||
struct SessionHandle *data = conn->data;
|
struct SessionHandle *data = conn->data;
|
||||||
int err;
|
|
||||||
long lerr;
|
|
||||||
int what;
|
|
||||||
char * str;
|
|
||||||
SSL_METHOD_QUAL SSL_METHOD *req_method=NULL;
|
SSL_METHOD_QUAL SSL_METHOD *req_method=NULL;
|
||||||
void *ssl_sessionid=NULL;
|
void *ssl_sessionid=NULL;
|
||||||
ASN1_TIME *certdate;
|
|
||||||
curl_socket_t sockfd = conn->sock[sockindex];
|
curl_socket_t sockfd = conn->sock[sockindex];
|
||||||
struct ssl_connect_data *connssl = &conn->ssl[sockindex];
|
struct ssl_connect_data *connssl = &conn->ssl[sockindex];
|
||||||
|
|
||||||
|
curlassert(ssl_connect_1 == connssl->connecting_state);
|
||||||
|
|
||||||
if(!ssl_seeded || data->set.ssl.random_file || data->set.ssl.egdsocket) {
|
if(!ssl_seeded || data->set.ssl.random_file || data->set.ssl.egdsocket) {
|
||||||
/* Make funny stuff to get random input */
|
/* Make funny stuff to get random input */
|
||||||
random_the_seed(data);
|
random_the_seed(data);
|
||||||
@@ -1297,134 +1295,150 @@ Curl_ossl_connect(struct connectdata *conn,
|
|||||||
return CURLE_SSL_CONNECT_ERROR;
|
return CURLE_SSL_CONNECT_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
while(1) {
|
connssl->connecting_state = ssl_connect_2;
|
||||||
int writefd;
|
return CURLE_OK;
|
||||||
int readfd;
|
}
|
||||||
long timeout_ms;
|
|
||||||
long has_passed;
|
|
||||||
|
|
||||||
/* Find out if any timeout is set. If not, use 300 seconds.
|
static CURLcode
|
||||||
Otherwise, figure out the most strict timeout of the two possible one
|
Curl_ossl_connect_step2(struct connectdata *conn,
|
||||||
and then how much time that has elapsed to know how much time we
|
int sockindex, long* timeout_ms)
|
||||||
allow for the connect call */
|
{
|
||||||
if(data->set.timeout || data->set.connecttimeout) {
|
struct SessionHandle *data = conn->data;
|
||||||
|
int err;
|
||||||
|
long has_passed;
|
||||||
|
struct ssl_connect_data *connssl = &conn->ssl[sockindex];
|
||||||
|
|
||||||
/* get the most strict timeout of the ones converted to milliseconds */
|
curlassert(ssl_connect_2 == connssl->connecting_state
|
||||||
if(data->set.timeout &&
|
|| ssl_connect_2_reading == connssl->connecting_state
|
||||||
(data->set.timeout>data->set.connecttimeout))
|
|| ssl_connect_2_writing == connssl->connecting_state);
|
||||||
timeout_ms = data->set.timeout*1000;
|
|
||||||
else
|
/* Find out if any timeout is set. If not, use 300 seconds.
|
||||||
timeout_ms = data->set.connecttimeout*1000;
|
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
|
else
|
||||||
/* no particular time-out has been set */
|
*timeout_ms = data->set.connecttimeout*1000;
|
||||||
timeout_ms= DEFAULT_CONNECT_TIMEOUT;
|
}
|
||||||
|
else
|
||||||
|
/* no particular time-out has been set */
|
||||||
|
*timeout_ms= DEFAULT_CONNECT_TIMEOUT;
|
||||||
|
|
||||||
/* Evaluate in milliseconds how much time that has passed */
|
/* Evaluate in milliseconds how much time that has passed */
|
||||||
has_passed = Curl_tvdiff(Curl_tvnow(), data->progress.t_startsingle);
|
has_passed = Curl_tvdiff(Curl_tvnow(), data->progress.t_startsingle);
|
||||||
|
|
||||||
/* subtract the passed time */
|
/* subtract the passed time */
|
||||||
timeout_ms -= has_passed;
|
*timeout_ms -= has_passed;
|
||||||
|
|
||||||
if(timeout_ms < 0) {
|
if(*timeout_ms < 0) {
|
||||||
/* a precaution, no need to continue if time already is up */
|
/* a precaution, no need to continue if time already is up */
|
||||||
failf(data, "SSL connection timeout");
|
failf(data, "SSL connection timeout");
|
||||||
return CURLE_OPERATION_TIMEOUTED;
|
return CURLE_OPERATION_TIMEOUTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
if(SSL_ERROR_WANT_READ == detail) {
|
||||||
|
connssl->connecting_state = ssl_connect_2_reading;
|
||||||
|
return CURLE_OK;
|
||||||
}
|
}
|
||||||
|
else if(SSL_ERROR_WANT_WRITE == detail) {
|
||||||
|
connssl->connecting_state = ssl_connect_2_writing;
|
||||||
|
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;
|
||||||
|
|
||||||
readfd = CURL_SOCKET_BAD;
|
connssl->connecting_state = ssl_connect_2; /* the connection failed,
|
||||||
writefd = CURL_SOCKET_BAD;
|
we're not waiting for
|
||||||
|
anything else. */
|
||||||
|
|
||||||
err = SSL_connect(connssl->handle);
|
errdetail = ERR_get_error(); /* Gets the earliest error code from the
|
||||||
|
thread's error queue and removes the
|
||||||
|
entry. */
|
||||||
|
|
||||||
/* 1 is fine
|
switch(errdetail) {
|
||||||
0 is "not successful but was shut down controlled"
|
case 0x1407E086:
|
||||||
<0 is "handshake was not successful, because a fatal error occurred" */
|
/* 1407E086:
|
||||||
if(1 != err) {
|
SSL routines:
|
||||||
int detail = SSL_get_error(connssl->handle, err);
|
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(SSL_ERROR_WANT_READ == detail)
|
/* detail is already set to the SSL error above */
|
||||||
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;
|
|
||||||
|
|
||||||
errdetail = ERR_get_error(); /* Gets the earliest error code from the
|
/* If we e.g. use SSLv2 request-method and the server doesn't like us
|
||||||
thread's error queue and removes the
|
* (RST connection etc.), OpenSSL gives no explanation whatsoever and
|
||||||
entry. */
|
* the SO_ERROR is also lost.
|
||||||
|
*/
|
||||||
switch(errdetail) {
|
if (CURLE_SSL_CONNECT_ERROR == rc && errdetail == 0) {
|
||||||
case 0x1407E086:
|
failf(data, "Unknown SSL protocol error in connection to %s:%d ",
|
||||||
/* 1407E086:
|
conn->host.name, conn->port);
|
||||||
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 */
|
|
||||||
|
|
||||||
/* 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;
|
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 */
|
else {
|
||||||
break;
|
/* we have been connected fine, we're not waiting for anything else. */
|
||||||
|
connssl->connecting_state = ssl_connect_3;
|
||||||
|
|
||||||
while(1) {
|
/* Informational message */
|
||||||
what = Curl_select(readfd, writefd, (int)timeout_ms);
|
infof (data, "SSL connection using %s\n",
|
||||||
if(what > 0)
|
SSL_get_cipher(connssl->handle));
|
||||||
/* 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() */
|
|
||||||
|
|
||||||
/* Informational message */
|
return CURLE_OK;
|
||||||
infof (data, "SSL connection using %s\n",
|
}
|
||||||
SSL_get_cipher(connssl->handle));
|
}
|
||||||
|
|
||||||
if(!ssl_sessionid) {
|
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];
|
||||||
|
|
||||||
|
curlassert(ssl_connect_3 == connssl->connecting_state);
|
||||||
|
|
||||||
|
if(Curl_ssl_getsessionid(conn, &ssl_sessionid, NULL)) {
|
||||||
/* Since this is not a cached session ID, then we want to stach this one
|
/* Since this is not a cached session ID, then we want to stach this one
|
||||||
in the cache! */
|
in the cache! */
|
||||||
SSL_SESSION *ssl_sessionid;
|
SSL_SESSION *ssl_sessionid;
|
||||||
@@ -1529,9 +1543,114 @@ Curl_ossl_connect(struct connectdata *conn,
|
|||||||
|
|
||||||
X509_free(connssl->server_cert);
|
X509_free(connssl->server_cert);
|
||||||
connssl->server_cert = NULL;
|
connssl->server_cert = NULL;
|
||||||
|
connssl->connecting_state = ssl_connect_done;
|
||||||
return retcode;
|
return retcode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static CURLcode
|
||||||
|
Curl_ossl_connect_common(struct connectdata *conn,
|
||||||
|
int sockindex,
|
||||||
|
bool nonblocking,
|
||||||
|
bool *done)
|
||||||
|
{
|
||||||
|
CURLcode retcode;
|
||||||
|
struct SessionHandle *data = conn->data;
|
||||||
|
struct ssl_connect_data *connssl = &conn->ssl[sockindex];
|
||||||
|
curl_socket_t sockfd = conn->sock[sockindex];
|
||||||
|
long timeout_ms;
|
||||||
|
|
||||||
|
if (ssl_connect_1==connssl->connecting_state) {
|
||||||
|
retcode = Curl_ossl_connect_step1(conn, sockindex);
|
||||||
|
if (retcode)
|
||||||
|
return retcode;
|
||||||
|
}
|
||||||
|
|
||||||
|
timeout_ms = 0;
|
||||||
|
while (ssl_connect_2 == connssl->connecting_state ||
|
||||||
|
ssl_connect_2_reading == connssl->connecting_state ||
|
||||||
|
ssl_connect_2_writing == connssl->connecting_state) {
|
||||||
|
|
||||||
|
/* 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) {
|
||||||
|
|
||||||
|
int writefd = ssl_connect_2_writing==
|
||||||
|
connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
|
||||||
|
int readfd = ssl_connect_2_reading==
|
||||||
|
connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
|
||||||
|
|
||||||
|
while(1) {
|
||||||
|
int what = Curl_select(readfd, writefd, nonblocking?0:(int)timeout_ms);
|
||||||
|
if(what > 0)
|
||||||
|
/* reabable or writable, go loop in the outer loop */
|
||||||
|
break;
|
||||||
|
else if(0 == what) {
|
||||||
|
if (nonblocking) {
|
||||||
|
*done = FALSE;
|
||||||
|
return CURLE_OK;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* 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() */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* get the timeout from step2 to avoid computing it twice. */
|
||||||
|
retcode = Curl_ossl_connect_step2(conn, sockindex, &timeout_ms);
|
||||||
|
if (retcode)
|
||||||
|
return retcode;
|
||||||
|
|
||||||
|
} /* repeat step2 until all transactions are done. */
|
||||||
|
|
||||||
|
|
||||||
|
if (ssl_connect_3==connssl->connecting_state) {
|
||||||
|
retcode = Curl_ossl_connect_step3(conn, sockindex);
|
||||||
|
if (retcode)
|
||||||
|
return retcode;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ssl_connect_done==connssl->connecting_state) {
|
||||||
|
*done = TRUE;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
*done = FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return CURLE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
CURLcode
|
||||||
|
Curl_ossl_connect_nonblocking(struct connectdata *conn,
|
||||||
|
int sockindex,
|
||||||
|
bool *done)
|
||||||
|
{
|
||||||
|
return Curl_ossl_connect_common(conn, sockindex, TRUE, done);
|
||||||
|
}
|
||||||
|
|
||||||
|
CURLcode
|
||||||
|
Curl_ossl_connect(struct connectdata *conn,
|
||||||
|
int sockindex)
|
||||||
|
{
|
||||||
|
CURLcode retcode;
|
||||||
|
bool done = FALSE;
|
||||||
|
|
||||||
|
retcode = Curl_ossl_connect_common(conn, sockindex, FALSE, &done);
|
||||||
|
if (retcode)
|
||||||
|
return retcode;
|
||||||
|
|
||||||
|
curlassert(done);
|
||||||
|
|
||||||
|
return CURLE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
/* return number of sent (non-SSL) bytes */
|
/* return number of sent (non-SSL) bytes */
|
||||||
int Curl_ossl_send(struct connectdata *conn,
|
int Curl_ossl_send(struct connectdata *conn,
|
||||||
int sockindex,
|
int sockindex,
|
||||||
|
|||||||
@@ -29,6 +29,9 @@
|
|||||||
|
|
||||||
#include "urldata.h"
|
#include "urldata.h"
|
||||||
CURLcode Curl_ossl_connect(struct connectdata *conn, int sockindex);
|
CURLcode Curl_ossl_connect(struct connectdata *conn, int sockindex);
|
||||||
|
CURLcode Curl_ossl_connect_nonblocking(struct connectdata *conn,
|
||||||
|
int sockindex,
|
||||||
|
bool *done);
|
||||||
void Curl_ossl_close(struct connectdata *conn); /* close a SSL connection */
|
void Curl_ossl_close(struct connectdata *conn); /* close a SSL connection */
|
||||||
/* tell OpenSSL to close down all open information regarding connections (and
|
/* tell OpenSSL to close down all open information regarding connections (and
|
||||||
thus session ID caching etc) */
|
thus session ID caching etc) */
|
||||||
|
|||||||
@@ -2990,6 +2990,8 @@ static CURLcode CreateConnection(struct SessionHandle *data,
|
|||||||
conn->curl_do_more = NULL;
|
conn->curl_do_more = NULL;
|
||||||
conn->curl_done = Curl_http_done;
|
conn->curl_done = Curl_http_done;
|
||||||
conn->curl_connect = Curl_http_connect;
|
conn->curl_connect = Curl_http_connect;
|
||||||
|
conn->curl_connecting = Curl_https_connecting;
|
||||||
|
conn->curl_proto_fdset = Curl_https_proto_fdset;
|
||||||
|
|
||||||
#else /* USE_SS */
|
#else /* USE_SS */
|
||||||
failf(data, LIBCURL_NAME
|
failf(data, LIBCURL_NAME
|
||||||
|
|||||||
@@ -128,13 +128,23 @@ struct krb4buffer {
|
|||||||
int eof_flag;
|
int eof_flag;
|
||||||
};
|
};
|
||||||
enum protection_level {
|
enum protection_level {
|
||||||
prot_clear,
|
prot_clear,
|
||||||
prot_safe,
|
prot_safe,
|
||||||
prot_confidential,
|
prot_confidential,
|
||||||
prot_private
|
prot_private
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* enum for the nonblocking SSL connection state machine */
|
||||||
|
typedef enum {
|
||||||
|
ssl_connect_1,
|
||||||
|
ssl_connect_2,
|
||||||
|
ssl_connect_2_reading,
|
||||||
|
ssl_connect_2_writing,
|
||||||
|
ssl_connect_3,
|
||||||
|
ssl_connect_done
|
||||||
|
} ssl_connect_state;
|
||||||
|
|
||||||
/* struct for data related to each SSL connection */
|
/* struct for data related to each SSL connection */
|
||||||
struct ssl_connect_data {
|
struct ssl_connect_data {
|
||||||
bool use; /* use ssl encrypted communications TRUE/FALSE */
|
bool use; /* use ssl encrypted communications TRUE/FALSE */
|
||||||
@@ -143,6 +153,7 @@ struct ssl_connect_data {
|
|||||||
SSL_CTX* ctx;
|
SSL_CTX* ctx;
|
||||||
SSL* handle;
|
SSL* handle;
|
||||||
X509* server_cert;
|
X509* server_cert;
|
||||||
|
ssl_connect_state connecting_state;
|
||||||
#endif /* USE_SSLEAY */
|
#endif /* USE_SSLEAY */
|
||||||
#ifdef USE_GNUTLS
|
#ifdef USE_GNUTLS
|
||||||
gnutls_session session;
|
gnutls_session session;
|
||||||
|
|||||||
Reference in New Issue
Block a user