schannel SSL: Made send method handle unexpected cases better
Implemented timeout loop in schannel_send while sending data. This is as close as I think we can get to write buffering; I put a big comment in to explain my thinking. With some committer adjustments
This commit is contained in:
parent
7d2abe27dd
commit
a15378e073
@ -40,7 +40,6 @@
|
||||
|
||||
/*
|
||||
* TODO list for TLS/SSL implementation:
|
||||
* - implement write buffering
|
||||
* - implement client certificate authentication
|
||||
* - implement custom server certificate validation
|
||||
* - implement cipher/algorithm option
|
||||
@ -681,14 +680,75 @@ schannel_send(struct connectdata *conn, int sockindex,
|
||||
|
||||
/* check if the message was encrypted */
|
||||
if(sspi_status == SEC_E_OK) {
|
||||
written = 0;
|
||||
|
||||
/* send the encrypted message including header, data and trailer */
|
||||
len = outbuf[0].cbBuffer + outbuf[1].cbBuffer + outbuf[2].cbBuffer;
|
||||
code = Curl_write_plain(conn, conn->sock[sockindex], data, len, &written);
|
||||
if((code != CURLE_OK) || (len != (size_t)written))
|
||||
*err = CURLE_SEND_ERROR;
|
||||
if(code != CURLE_OK)
|
||||
written = -1;
|
||||
/* TODO: implement write buffering */
|
||||
|
||||
/*
|
||||
It's important to send the full message which includes the header,
|
||||
encrypted payload, and trailer. Until the client receives all the
|
||||
data a coherent message has not been delivered and the client
|
||||
can't read any of it.
|
||||
|
||||
If we wanted to buffer the unwritten encrypted bytes, we would
|
||||
tell the client that all data it has requested to be sent has been
|
||||
sent. The unwritten encrypted bytes would be the first bytes to
|
||||
send on the next invocation.
|
||||
Here's the catch with this - if we tell the client that all the
|
||||
bytes have been sent, will the client call this method again to
|
||||
send the buffered data? Looking at who calls this function, it
|
||||
seems the answer is NO.
|
||||
*/
|
||||
|
||||
/* send entire message or fail */
|
||||
while(len > (size_t)written) {
|
||||
ssize_t this_write;
|
||||
long timeleft;
|
||||
int what;
|
||||
|
||||
this_write = 0;
|
||||
|
||||
timeleft = Curl_timeleft(conn->data, NULL, TRUE);
|
||||
if(timeleft < 0) {
|
||||
/* we already got the timeout */
|
||||
failf(conn->data, "schannel: timed out sending data "
|
||||
"(bytes sent: %zd)", written);
|
||||
*err = CURLE_OPERATION_TIMEDOUT;
|
||||
written = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
what = Curl_socket_ready(CURL_SOCKET_BAD, conn->sock[sockindex],
|
||||
timeleft);
|
||||
if(what < 0) {
|
||||
/* fatal error */
|
||||
failf(conn->data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
|
||||
*err = CURLE_SEND_ERROR;
|
||||
written = -1;
|
||||
break;
|
||||
}
|
||||
else if(0 == what) {
|
||||
failf(conn->data, "schannel: timed out sending data "
|
||||
"(bytes sent: %zd)", written);
|
||||
*err = CURLE_OPERATION_TIMEDOUT;
|
||||
written = -1;
|
||||
break;
|
||||
}
|
||||
/* socket is writable */
|
||||
|
||||
code = Curl_write_plain(conn, conn->sock[sockindex], data + written,
|
||||
len - written, &this_write);
|
||||
if(code == CURLE_AGAIN)
|
||||
continue;
|
||||
else if(code != CURLE_OK) {
|
||||
*err = code;
|
||||
written = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
written += this_write;
|
||||
}
|
||||
}
|
||||
else if(sspi_status == SEC_E_INSUFFICIENT_MEMORY) {
|
||||
*err = CURLE_OUT_OF_MEMORY;
|
||||
@ -699,6 +759,11 @@ schannel_send(struct connectdata *conn, int sockindex,
|
||||
|
||||
free(data);
|
||||
|
||||
if(len == (size_t)written)
|
||||
/* Encrypted message including header, data and trailer entirely sent.
|
||||
The return value is the number of unencrypted bytes that were sent. */
|
||||
written = outbuf[1].cbBuffer;
|
||||
|
||||
return written;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user