summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoragl@chromium.org <agl@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-09-08 16:41:14 +0000
committeragl@chromium.org <agl@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-09-08 16:41:14 +0000
commit9ae2ee0b2e657a1556edb9646c032ab50b291f09 (patch)
tree603678b8945a866c679d633c3e4020093fb2dc94
parentb5f2ca399b0ddc05df4406054cb515863370ebef (diff)
downloadchromium_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.c26
-rw-r--r--net/base/nss_memio.h8
-rw-r--r--net/socket/ssl_client_socket_nss.cc62
-rw-r--r--net/socket/ssl_client_socket_nss.h3
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_;