diff options
| -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;  } | 
