diff options
| author | Mark Salisbury <mark.salisbury@hp.com> | 2012-06-20 00:14:17 +0200 | 
|---|---|---|
| committer | Yang Tse <yangsita@gmail.com> | 2012-06-20 00:16:40 +0200 | 
| commit | a15378e0730fa0af0a11be512f19acc50d0f1a84 (patch) | |
| tree | 14f98b56d03e134b876d9d3d78c922b047e5f3e4 | |
| parent | 7d2abe27ddf5b5aa0edeb619ef95db6fc2c98afe (diff) | |
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
| -rw-r--r-- | lib/curl_schannel.c | 79 | 
1 files changed, 72 insertions, 7 deletions
| diff --git a/lib/curl_schannel.c b/lib/curl_schannel.c index ba010171e..8b2f5ea72 100644 --- a/lib/curl_schannel.c +++ b/lib/curl_schannel.c @@ -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;  } | 
