diff options
author | agl@chromium.org <agl@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-09-08 16:41:14 +0000 |
---|---|---|
committer | agl@chromium.org <agl@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-09-08 16:41:14 +0000 |
commit | 9ae2ee0b2e657a1556edb9646c032ab50b291f09 (patch) | |
tree | 603678b8945a866c679d633c3e4020093fb2dc94 | |
parent | b5f2ca399b0ddc05df4406054cb515863370ebef (diff) | |
download | chromium_src-9ae2ee0b2e657a1556edb9646c032ab50b291f09.zip chromium_src-9ae2ee0b2e657a1556edb9646c032ab50b291f09.tar.gz chromium_src-9ae2ee0b2e657a1556edb9646c032ab50b291f09.tar.bz2 |
net: When using False Start merge Finished and Application Data records.
When using False Start, this patch causes NSS to perform a single
write which contains the ClientKeyExchange, ChangeCipherSpec, Finished
and first application data record.
This removes a source of non-determinism when dealing with False Start
intolerant servers. Previously, Chrome may, or may not work depending
on network timing.
BUG=none
TEST=none
http://codereview.chromium.org/3331005/show
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@58838 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | net/base/nss_memio.c | 26 | ||||
-rw-r--r-- | net/base/nss_memio.h | 8 | ||||
-rw-r--r-- | net/socket/ssl_client_socket_nss.cc | 62 | ||||
-rw-r--r-- | net/socket/ssl_client_socket_nss.h | 3 |
4 files changed, 68 insertions, 31 deletions
diff --git a/net/base/nss_memio.c b/net/base/nss_memio.c index 5f7fd00..8b45c49 100644 --- a/net/base/nss_memio.c +++ b/net/base/nss_memio.c @@ -70,6 +70,9 @@ static void memio_buffer_destroy(struct memio_buffer *mb); /* How many bytes can be read out of the buffer without wrapping */ static int memio_buffer_used_contiguous(const struct memio_buffer *mb); +/* How many bytes exist after the wrap? */ +static int memio_buffer_wrapped_bytes(const struct memio_buffer *mb); + /* How many bytes can be written into the buffer without wrapping */ static int memio_buffer_unused_contiguous(const struct memio_buffer *mb); @@ -103,6 +106,12 @@ static int memio_buffer_used_contiguous(const struct memio_buffer *mb) return (((mb->tail >= mb->head) ? mb->tail : mb->bufsize) - mb->head); } +/* How many bytes exist after the wrap? */ +static int memio_buffer_wrapped_bytes(const struct memio_buffer *mb) +{ + return (mb->tail >= mb->head) ? 0 : mb->tail; +} + /* How many bytes can be written into the buffer without wrapping */ static int memio_buffer_unused_contiguous(const struct memio_buffer *mb) { @@ -399,13 +408,17 @@ void memio_PutReadResult(memio_Private *secret, int bytes_read) } } -int memio_GetWriteParams(memio_Private *secret, const char **buf) +void memio_GetWriteParams(memio_Private *secret, + const char **buf1, unsigned int *len1, + const char **buf2, unsigned int *len2) { struct memio_buffer* mb = &((PRFilePrivate *)secret)->writebuf; PR_ASSERT(mb->bufsize); - *buf = &mb->buf[mb->head]; - return memio_buffer_used_contiguous(mb); + *buf1 = &mb->buf[mb->head]; + *len1 = memio_buffer_used_contiguous(mb); + *buf2 = mb->buf; + *len2 = memio_buffer_wrapped_bytes(mb); } void memio_PutWriteResult(memio_Private *secret, int bytes_written) @@ -415,8 +428,8 @@ void memio_PutWriteResult(memio_Private *secret, int bytes_written) if (bytes_written > 0) { mb->head += bytes_written; - if (mb->head == mb->bufsize) - mb->head = 0; + if (mb->head >= mb->bufsize) + mb->head -= mb->bufsize; } else if (bytes_written < 0) { mb->last_err = bytes_written; } @@ -453,11 +466,13 @@ int main() CHECKEQ(memio_buffer_unused_contiguous(&mb), TEST_BUFLEN-1-5); CHECKEQ(memio_buffer_used_contiguous(&mb), 5); + CHECKEQ(memio_buffer_wrapped_bytes(&mb), 0); CHECKEQ(memio_buffer_put(&mb, "!", 1), 1); CHECKEQ(memio_buffer_unused_contiguous(&mb), 0); CHECKEQ(memio_buffer_used_contiguous(&mb), 6); + CHECKEQ(memio_buffer_wrapped_bytes(&mb), 0); CHECKEQ(memio_buffer_get(&mb, buf, 6), 6); CHECKEQ(memcmp(buf, "howdy!", 6), 0); @@ -468,6 +483,7 @@ int main() CHECKEQ(memio_buffer_put(&mb, "01234", 5), 5); CHECKEQ(memio_buffer_used_contiguous(&mb), 1); + CHECKEQ(memio_buffer_wrapped_bytes(&mb), 4); CHECKEQ(memio_buffer_unused_contiguous(&mb), TEST_BUFLEN-1-5); CHECKEQ(memio_buffer_put(&mb, "5", 1), 1); diff --git a/net/base/nss_memio.h b/net/base/nss_memio.h index c93e91f..49d7cbc 100644 --- a/net/base/nss_memio.h +++ b/net/base/nss_memio.h @@ -68,10 +68,12 @@ int memio_GetReadParams(memio_Private *secret, char **buf); void memio_PutReadResult(memio_Private *secret, int bytes_read); /* Ask memio what data it has to send to the network. - * Returns buffer space available to read into, or 0 if none available. - * Puts current buffer position into *buf. + * Returns up to two buffers of data by writing the positions and lengths into + * |buf1|, |len1| and |buf2|, |len2|. */ -int memio_GetWriteParams(memio_Private *secret, const char **buf); +void memio_GetWriteParams(memio_Private *secret, + const char **buf1, unsigned int *len1, + const char **buf2, unsigned int *len2); /* Tell memio how many bytes were sent to the network. * If bytes_written is < 0, it is treated as an NSPR error code. diff --git a/net/socket/ssl_client_socket_nss.cc b/net/socket/ssl_client_socket_nss.cc index f46bfcc..5da49cf 100644 --- a/net/socket/ssl_client_socket_nss.cc +++ b/net/socket/ssl_client_socket_nss.cc @@ -336,6 +336,7 @@ SSLClientSocketNSS::SSLClientSocketNSS(ClientSocketHandle* transport_socket, this, &SSLClientSocketNSS::BufferRecvComplete)), transport_send_busy_(false), transport_recv_busy_(false), + corked_(false), ALLOW_THIS_IN_INITIALIZER_LIST(handshake_io_callback_( this, &SSLClientSocketNSS::OnHandshakeIOComplete)), transport_(transport_socket), @@ -723,6 +724,7 @@ int SSLClientSocketNSS::Write(IOBuffer* buf, int buf_len, user_write_buf_ = buf; user_write_buf_len_ = buf_len; + corked_ = false; int rv = DoWriteLoop(OK); if (rv == ERR_IO_PENDING) { @@ -1109,38 +1111,35 @@ bool SSLClientSocketNSS::DoTransportIO() { // > 0 for bytes transferred immediately, // < 0 for error (or the non-error ERR_IO_PENDING). int SSLClientSocketNSS::BufferSend(void) { - if (transport_send_busy_) return ERR_IO_PENDING; + if (transport_send_busy_) + return ERR_IO_PENDING; - int nsent = 0; EnterFunction(""); - // nss_bufs_ is a circular buffer. It may have two contiguous parts - // (before and after the wrap). So this for loop needs two iterations. - for (int i = 0; i < 2; ++i) { - const char* buf; - int nb = memio_GetWriteParams(nss_bufs_, &buf); - if (!nb) - break; - - scoped_refptr<IOBuffer> send_buffer = new IOBuffer(nb); - memcpy(send_buffer->data(), buf, nb); - int rv = transport_->socket()->Write(send_buffer, nb, - &buffer_send_callback_); + const char* buf1; + const char* buf2; + unsigned int len1, len2; + memio_GetWriteParams(nss_bufs_, &buf1, &len1, &buf2, &len2); + const unsigned int len = len1 + len2; + + if (corked_ && len < kRecvBufferSize / 2) + return 0; + + int rv = 0; + if (len) { + scoped_refptr<IOBuffer> send_buffer = new IOBuffer(len); + memcpy(send_buffer->data(), buf1, len1); + memcpy(send_buffer->data() + len1, buf2, len2); + rv = transport_->socket()->Write(send_buffer, len, + &buffer_send_callback_); if (rv == ERR_IO_PENDING) { transport_send_busy_ = true; - break; } else { memio_PutWriteResult(nss_bufs_, MapErrorToNSS(rv)); - if (rv < 0) { - // Return the error even if the previous Write succeeded. - nsent = rv; - break; - } - nsent += rv; } } - LeaveFunction(nsent); - return nsent; + LeaveFunction(rv); + return rv; } void SSLClientSocketNSS::BufferSendComplete(int result) { @@ -1292,6 +1291,23 @@ SECStatus SSLClientSocketNSS::OwnAuthCertHandler(void* arg, PRFileDesc* socket, PRBool checksig, PRBool is_server) { +#ifdef SSL_ENABLE_FALSE_START + // In the event that we are False Starting this connection, we wish to send + // out the Finished message and first application data record in the same + // packet. This prevents non-determinism when talking to False Start + // intolerant servers which, otherwise, might see the two messages in + // different reads or not, depending on network conditions. + PRBool false_start = 0; + SECStatus rv = SSL_OptionGet(socket, SSL_ENABLE_FALSE_START, &false_start); + if (rv != SECSuccess) + NOTREACHED(); + if (false_start) { + SSLClientSocketNSS* that = reinterpret_cast<SSLClientSocketNSS*>(arg); + if (!that->handshake_callback_called_) + that->corked_ = true; + } +#endif + // Tell NSS to not verify the certificate. return SECSuccess; } diff --git a/net/socket/ssl_client_socket_nss.h b/net/socket/ssl_client_socket_nss.h index c43b718..3796826 100644 --- a/net/socket/ssl_client_socket_nss.h +++ b/net/socket/ssl_client_socket_nss.h @@ -124,6 +124,9 @@ class SSLClientSocketNSS : public SSLClientSocket { CompletionCallbackImpl<SSLClientSocketNSS> buffer_recv_callback_; bool transport_send_busy_; bool transport_recv_busy_; + // corked_ is true if we are currently suspending writes to the network. This + // is named after the similar kernel flag, TCP_CORK. + bool corked_; scoped_refptr<IOBuffer> recv_buffer_; CompletionCallbackImpl<SSLClientSocketNSS> handshake_io_callback_; |