refactorize interface of Curl_ssl_recv/Curl_ssl_send

This commit is contained in:
Kamil Dudka 2010-04-04 23:37:18 +02:00
parent 7425db3fab
commit ff8711135e
10 changed files with 127 additions and 97 deletions

View File

@ -9,6 +9,8 @@
Kamil Dudka (4 Apr 2010)
- Eliminated a race condition in Curl_resolv_timeout().
- Refactorized interface of Curl_ssl_recv()/Curl_ssl_send().
Daniel Stenberg (1 Apr 2010)
- Matt Wixson found and fixed a bug in the SCP/SFTP area where the code
treated a 0 return code from libssh2 to be the same as EAGAIN while in

View File

@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2009, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2010, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@ -638,18 +638,21 @@ Curl_gtls_connect(struct connectdata *conn,
}
/* return number of sent (non-SSL) bytes */
/* for documentation see Curl_ssl_send() in sslgen.h */
ssize_t Curl_gtls_send(struct connectdata *conn,
int sockindex,
const void *mem,
size_t len)
size_t len,
int *curlcode)
{
ssize_t rc = gnutls_record_send(conn->ssl[sockindex].session, mem, len);
if(rc < 0 ) {
if(rc == GNUTLS_E_AGAIN)
return 0; /* EWOULDBLOCK equivalent */
rc = -1; /* generic error code for send failure */
*curlcode = (rc == GNUTLS_E_AGAIN)
? /* EWOULDBLOCK */ -1
: CURLE_SEND_ERROR;
rc = -1;
}
return rc;
@ -748,22 +751,18 @@ int Curl_gtls_shutdown(struct connectdata *conn, int sockindex)
return retval;
}
/*
* If the read would block we return -1 and set 'wouldblock' to TRUE.
* Otherwise we return the amount of data read. Other errors should return -1
* and set 'wouldblock' to FALSE.
*/
/* for documentation see Curl_ssl_recv() in sslgen.h */
ssize_t Curl_gtls_recv(struct connectdata *conn, /* connection data */
int num, /* socketindex */
char *buf, /* store read data here */
size_t buffersize, /* max amount to read */
bool *wouldblock)
int *curlcode)
{
ssize_t ret;
ret = gnutls_record_recv(conn->ssl[num].session, buf, buffersize);
if((ret == GNUTLS_E_AGAIN) || (ret == GNUTLS_E_INTERRUPTED)) {
*wouldblock = TRUE;
*curlcode = -1;
return -1;
}
@ -773,20 +772,22 @@ ssize_t Curl_gtls_recv(struct connectdata *conn, /* connection data */
CURLcode rc = handshake(conn, conn->ssl[num].session, num, FALSE);
if(rc)
/* handshake() writes error message on its own */
return rc;
*wouldblock = TRUE; /* then return as if this was a wouldblock */
*curlcode = rc;
else
*curlcode = -1; /* then return as if this was a wouldblock */
return -1;
}
*wouldblock = FALSE;
if(!ret) {
failf(conn->data, "Peer closed the TLS connection");
*curlcode = CURLE_RECV_ERROR;
return -1;
}
if(ret < 0) {
failf(conn->data, "GnuTLS recv error (%d): %s",
(int)ret, gnutls_strerror((int)ret));
*curlcode = CURLE_RECV_ERROR;
return -1;
}

View File

@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2008, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2010, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@ -35,14 +35,14 @@ void Curl_gtls_close_all(struct SessionHandle *data);
/* close a SSL connection */
void Curl_gtls_close(struct connectdata *conn, int sockindex);
/* return number of sent (non-SSL) bytes */
/* for documentation see Curl_ssl_send() in sslgen.h */
ssize_t Curl_gtls_send(struct connectdata *conn, int sockindex,
const void *mem, size_t len);
ssize_t Curl_gtls_recv(struct connectdata *conn, /* connection data */
int num, /* socketindex */
char *buf, /* store read data here */
size_t buffersize, /* max amount to read */
bool *wouldblock);
const void *mem, size_t len, int *curlcode);
/* for documentation see Curl_ssl_recv() in sslgen.h */
ssize_t Curl_gtls_recv(struct connectdata *conn, int num, char *buf,
size_t buffersize, int *curlcode);
void Curl_gtls_session_free(void *ptr);
size_t Curl_gtls_version(char *buffer, size_t size);
int Curl_gtls_shutdown(struct connectdata *conn, int sockindex);

View File

@ -1340,47 +1340,50 @@ CURLcode Curl_nss_connect(struct connectdata *conn, int sockindex)
return curlerr;
}
/* return number of sent (non-SSL) bytes */
/* for documentation see Curl_ssl_send() in sslgen.h */
int Curl_nss_send(struct connectdata *conn, /* connection data */
int sockindex, /* socketindex */
const void *mem, /* send this data */
size_t len) /* amount to write */
size_t len, /* amount to write */
int *curlcode)
{
int rc;
rc = PR_Send(conn->ssl[sockindex].handle, mem, (int)len, 0, -1);
if(rc < 0) {
failf(conn->data, "SSL write: error %d", PR_GetError());
PRInt32 err = PR_GetError();
if(err == PR_WOULD_BLOCK_ERROR)
*curlcode = -1; /* EWOULDBLOCK */
else {
failf(conn->data, "SSL write: error %d", err);
*curlcode = CURLE_SEND_ERROR;
}
return -1;
}
return rc; /* number of bytes */
}
/*
* If the read would block we return -1 and set 'wouldblock' to TRUE.
* Otherwise we return the amount of data read. Other errors should return -1
* and set 'wouldblock' to FALSE.
*/
/* for documentation see Curl_ssl_recv() in sslgen.h */
ssize_t Curl_nss_recv(struct connectdata * conn, /* connection data */
int num, /* socketindex */
char *buf, /* store read data here */
size_t buffersize, /* max amount to read */
bool * wouldblock)
int *curlcode)
{
ssize_t nread;
nread = PR_Recv(conn->ssl[num].handle, buf, (int)buffersize, 0, -1);
*wouldblock = FALSE;
if(nread < 0) {
/* failed SSL read */
PRInt32 err = PR_GetError();
if(err == PR_WOULD_BLOCK_ERROR) {
*wouldblock = TRUE;
return -1; /* basically EWOULDBLOCK */
if(err == PR_WOULD_BLOCK_ERROR)
*curlcode = -1; /* EWOULDBLOCK */
else {
failf(conn->data, "SSL read: errno %d", err);
*curlcode = CURLE_RECV_ERROR;
}
failf(conn->data, "SSL read: errno %d", err);
return -1;
}
return nread;

View File

@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2008, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2010, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@ -42,15 +42,19 @@ int Curl_nss_close_all(struct SessionHandle *data);
int Curl_nss_init(void);
void Curl_nss_cleanup(void);
/* for documentation see Curl_ssl_send() in sslgen.h */
int Curl_nss_send(struct connectdata *conn,
int sockindex,
const void *mem,
size_t len);
size_t len,
int *curlcode);
/* for documentation see Curl_ssl_recv() in sslgen.h */
ssize_t Curl_nss_recv(struct connectdata *conn, /* connection data */
int num, /* socketindex */
char *buf, /* store read data here */
size_t buffersize, /* max amount to read */
bool *wouldblock);
int *curlcode);
size_t Curl_nss_version(char *buffer, size_t size);
int Curl_nss_check_cxn(struct connectdata *cxn);

View File

@ -268,6 +268,9 @@ static ssize_t send_plain(struct connectdata *conn,
/*
* Curl_write() is an internal write function that sends data to the
* server. Works with plain sockets, SCP, SSL or kerberos.
*
* If the write would block (EWOULDBLOCK), we return CURLE_OK and
* (*written == 0). Otherwise we return regular CURLcode value.
*/
CURLcode Curl_write(struct connectdata *conn,
curl_socket_t sockfd,
@ -276,11 +279,11 @@ CURLcode Curl_write(struct connectdata *conn,
ssize_t *written)
{
ssize_t bytes_written;
CURLcode retcode;
int curlcode = CURLE_OK;
int num = (sockfd == conn->sock[SECONDARYSOCKET]);
if(conn->ssl[num].state == ssl_connection_complete)
bytes_written = Curl_ssl_send(conn, num, mem, len);
bytes_written = Curl_ssl_send(conn, num, mem, len, &curlcode);
else if(Curl_ssh_enabled(conn, PROT_SCP))
bytes_written = Curl_scp_send(conn, num, mem, len);
else if(Curl_ssh_enabled(conn, PROT_SFTP))
@ -291,9 +294,24 @@ CURLcode Curl_write(struct connectdata *conn,
bytes_written = send_plain(conn, num, mem, len);
*written = bytes_written;
retcode = (-1 != bytes_written)?CURLE_OK:CURLE_SEND_ERROR;
if(-1 != bytes_written)
/* we completely ignore the curlcode value when -1 is not returned */
return CURLE_OK;
return retcode;
/* handle EWOULDBLOCK or a send failure */
switch(curlcode) {
case /* EWOULDBLOCK */ -1:
*written = /* EWOULDBLOCK */ 0;
return CURLE_OK;
case CURLE_OK:
/* general send failure */
return CURLE_SEND_ERROR;
default:
/* we got a specific curlcode, forward it */
return (CURLcode)curlcode;
}
}
/*
@ -535,13 +553,11 @@ int Curl_read(struct connectdata *conn, /* connection data */
}
if(conn->ssl[num].state == ssl_connection_complete) {
nread = Curl_ssl_recv(conn, num, buffertofill, bytesfromsocket);
int curlcode;
nread = Curl_ssl_recv(conn, num, buffertofill, bytesfromsocket, &curlcode);
if(nread == -1)
return -1; /* -1 from Curl_ssl_recv() means EWOULDBLOCK */
else if(nread == -2)
/* -2 from Curl_ssl_recv() means a true error, not EWOULDBLOCK */
return CURLE_RECV_ERROR;
return curlcode;
}
else if(Curl_ssh_enabled(conn, (PROT_SCP|PROT_SFTP))) {
if(conn->protocol & PROT_SCP)

View File

@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2009, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2010, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@ -408,38 +408,22 @@ struct curl_slist *Curl_ssl_engines_list(struct SessionHandle *data)
return curlssl_engines_list(data);
}
/* return number of sent (non-SSL) bytes; -1 on error */
ssize_t Curl_ssl_send(struct connectdata *conn,
int sockindex,
const void *mem,
size_t len)
size_t len,
int *curlcode)
{
return curlssl_send(conn, sockindex, mem, len);
return curlssl_send(conn, sockindex, mem, len, curlcode);
}
/* return number of received (decrypted) bytes */
/*
* If the read would block (EWOULDBLOCK) we return -1. If an error occurs during
* the read, we return -2. Otherwise we return the count of bytes transfered.
*/
ssize_t Curl_ssl_recv(struct connectdata *conn, /* connection data */
int sockindex, /* socketindex */
char *mem, /* store read data here */
size_t len) /* max amount to read */
ssize_t Curl_ssl_recv(struct connectdata *conn,
int sockindex,
char *mem,
size_t len,
int *curlcode)
{
ssize_t nread;
bool block = FALSE;
nread = curlssl_recv(conn, sockindex, mem, len, &block);
if(nread == -1) {
if(!block)
return -2; /* this is a true error, not EWOULDBLOCK */
else
return -1; /* EWOULDBLOCK */
}
return nread;
return curlssl_recv(conn, sockindex, mem, len, curlcode);
}

View File

@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2008, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2008, 2010, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@ -44,14 +44,29 @@ CURLcode Curl_ssl_set_engine(struct SessionHandle *data, const char *engine);
/* Sets engine as default for all SSL operations */
CURLcode Curl_ssl_set_engine_default(struct SessionHandle *data);
struct curl_slist *Curl_ssl_engines_list(struct SessionHandle *data);
ssize_t Curl_ssl_send(struct connectdata *conn,
int sockindex,
const void *mem,
size_t len);
/* If the write would block (EWOULDBLOCK) or fail, we we return -1.
* The error or -1 (for EWOULDBLOCK) is then stored in *curlcode.
* Otherwise we return the count of (non-SSL) bytes transfered.
*/
ssize_t Curl_ssl_send(struct connectdata *conn, /* connection data */
int sockindex, /* socketindex */
const void *mem, /* data to write */
size_t len, /* max amount to write */
int *curlcode); /* error to return,
-1 means EWOULDBLOCK */
/* If the read would block (EWOULDBLOCK) or fail, we we return -1.
* The error or -1 (for EWOULDBLOCK) is then stored in *curlcode.
* Otherwise we return the count of (non-SSL) bytes transfered.
*/
ssize_t Curl_ssl_recv(struct connectdata *conn, /* connection data */
int sockindex, /* socketindex */
char *mem, /* store read data here */
size_t len); /* max amount to read */
size_t len, /* max amount to read */
int *curlcode); /* error to return,
-1 means EWOULDBLOCK */
/* init the SSL session ID cache */
CURLcode Curl_ssl_initsessions(struct SessionHandle *, long);
size_t Curl_ssl_version(char *buffer, size_t size);

View File

@ -2482,11 +2482,12 @@ bool Curl_ossl_data_pending(const struct connectdata *conn,
return FALSE;
}
/* return number of sent (non-SSL) bytes */
/* for documentation see Curl_ssl_send() in sslgen.h */
ssize_t Curl_ossl_send(struct connectdata *conn,
int sockindex,
const void *mem,
size_t len)
size_t len,
int *curlcode)
{
/* SSL_write() is said to return 'int' while write() and send() returns
'size_t' */
@ -2509,10 +2510,12 @@ ssize_t Curl_ossl_send(struct connectdata *conn,
/* The operation did not complete; the same TLS/SSL I/O function
should be called again later. This is basicly an EWOULDBLOCK
equivalent. */
return 0;
*curlcode = /* EWOULDBLOCK */ -1;
return -1;
case SSL_ERROR_SYSCALL:
failf(conn->data, "SSL_write() returned SYSCALL, errno = %d",
SOCKERRNO);
*curlcode = CURLE_SEND_ERROR;
return -1;
case SSL_ERROR_SSL:
/* A failure in the SSL library occurred, usually a protocol error.
@ -2520,25 +2523,23 @@ ssize_t Curl_ossl_send(struct connectdata *conn,
sslerror = ERR_get_error();
failf(conn->data, "SSL_write() error: %s",
ERR_error_string(sslerror, error_buffer));
*curlcode = CURLE_SEND_ERROR;
return -1;
}
/* a true error */
failf(conn->data, "SSL_write() return error %d", err);
*curlcode = CURLE_SEND_ERROR;
return -1;
}
return (ssize_t)rc; /* number of bytes */
}
/*
* If the read would block we return -1 and set 'wouldblock' to TRUE.
* Otherwise we return the amount of data read. Other errors should return -1
* and set 'wouldblock' to FALSE.
*/
/* for documentation see Curl_ssl_recv() in sslgen.h */
ssize_t Curl_ossl_recv(struct connectdata *conn, /* connection data */
int num, /* socketindex */
char *buf, /* store read data here */
size_t buffersize, /* max amount to read */
bool *wouldblock)
int *curlcode)
{
char error_buffer[120]; /* OpenSSL documents that this must be at
least 120 bytes long. */
@ -2548,7 +2549,6 @@ ssize_t Curl_ossl_recv(struct connectdata *conn, /* connection data */
buffsize = (buffersize > (size_t)INT_MAX) ? INT_MAX : (int)buffersize;
nread = (ssize_t)SSL_read(conn->ssl[num].handle, buf, buffsize);
*wouldblock = FALSE;
if(nread < 0) {
/* failed SSL_read */
int err = SSL_get_error(conn->ssl[num].handle, (int)nread);
@ -2560,14 +2560,15 @@ ssize_t Curl_ossl_recv(struct connectdata *conn, /* connection data */
case SSL_ERROR_WANT_READ:
case SSL_ERROR_WANT_WRITE:
/* there's data pending, re-invoke SSL_read() */
*wouldblock = TRUE;
return -1; /* basically EWOULDBLOCK */
*curlcode = -1; /* EWOULDBLOCK */
return -1;
default:
/* openssl/ssl.h says "look at error stack/return value/errno" */
sslerror = ERR_get_error();
failf(conn->data, "SSL read: %s, errno %d",
ERR_error_string(sslerror, error_buffer),
SOCKERRNO);
*curlcode = CURLE_RECV_ERROR;
return -1;
}
}

View File

@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2008, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2010, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@ -56,15 +56,19 @@ struct curl_slist *Curl_ossl_engines_list(struct SessionHandle *data);
int Curl_ossl_init(void);
void Curl_ossl_cleanup(void);
/* for documentation see Curl_ssl_send() in sslgen.h */
ssize_t Curl_ossl_send(struct connectdata *conn,
int sockindex,
const void *mem,
size_t len);
size_t len,
int *curlcode);
/* for documentation see Curl_ssl_recv() in sslgen.h */
ssize_t Curl_ossl_recv(struct connectdata *conn, /* connection data */
int num, /* socketindex */
char *buf, /* store read data here */
size_t buffersize, /* max amount to read */
bool *wouldblock);
int *curlcode);
size_t Curl_ossl_version(char *buffer, size_t size);
int Curl_ossl_check_cxn(struct connectdata *cxn);