Chromium Code Reviews| Index: remoting/protocol/buffered_socket_writer.cc |
| diff --git a/remoting/protocol/buffered_socket_writer.cc b/remoting/protocol/buffered_socket_writer.cc |
| index f0ab9f22d1c82ded0872e614f9ba38d36ed04c7b..496e1c551028ca2ed15fd9f2521ce01f610c37ab 100644 |
| --- a/remoting/protocol/buffered_socket_writer.cc |
| +++ b/remoting/protocol/buffered_socket_writer.cc |
| @@ -6,7 +6,9 @@ |
| #include "base/bind.h" |
| #include "base/location.h" |
| +#include "base/single_thread_task_runner.h" |
| #include "base/stl_util.h" |
| +#include "base/thread_task_runner_handle.h" |
| #include "net/base/net_errors.h" |
| namespace remoting { |
| @@ -16,30 +18,20 @@ class BufferedSocketWriterBase::PendingPacket { |
| public: |
| PendingPacket(scoped_refptr<net::IOBufferWithSize> data, |
| const base::Closure& done_task) |
| - : data_(data), |
| - done_task_(done_task) { |
| + : data(data), |
| + done_task(done_task) { |
| } |
| - ~PendingPacket() { |
| - if (!done_task_.is_null()) |
| - done_task_.Run(); |
| - } |
| - |
| - net::IOBufferWithSize* data() { |
| - return data_; |
| - } |
| - |
| - private: |
| - scoped_refptr<net::IOBufferWithSize> data_; |
| - base::Closure done_task_; |
| - DISALLOW_COPY_AND_ASSIGN(PendingPacket); |
| + scoped_refptr<net::IOBufferWithSize> data; |
| + base::Closure done_task; |
| }; |
| BufferedSocketWriterBase::BufferedSocketWriterBase() |
| : buffer_size_(0), |
| socket_(NULL), |
| write_pending_(false), |
| - closed_(false) { |
| + closed_(false), |
| + destroyed_flag_(NULL) { |
| } |
| void BufferedSocketWriterBase::Init(net::Socket* socket, |
| @@ -54,6 +46,7 @@ bool BufferedSocketWriterBase::Write( |
| scoped_refptr<net::IOBufferWithSize> data, const base::Closure& done_task) { |
| DCHECK(CalledOnValidThread()); |
| DCHECK(socket_); |
| + DCHECK(data.get()); |
| // Don't write after Close(). |
| if (closed_) |
| @@ -91,35 +84,52 @@ void BufferedSocketWriterBase::DoWrite() { |
| current_packet, current_packet_size, |
| base::Bind(&BufferedSocketWriterBase::OnWritten, |
| base::Unretained(this))); |
| - if (result >= 0) { |
| - AdvanceBufferPosition(result); |
| + bool write_again = false; |
| + HandleWriteResult(result, &write_again); |
| + if (!write_again) |
| + return; |
| + } |
| +} |
| + |
| +void BufferedSocketWriterBase::HandleWriteResult(int result, |
| + bool* write_again) { |
|
simonmorris
2012/07/31 20:19:50
Can't HandleWriteResult just return write_again?
Sergey Ulanov
2012/07/31 21:37:53
It can by, it's more readable this way because the
simonmorris
2012/07/31 22:20:13
I think this way makes the call sites unnecessaril
|
| + *write_again = false; |
| + if (result < 0) { |
| + if (result == net::ERR_IO_PENDING) { |
| + write_pending_ = true; |
| } else { |
| - if (result == net::ERR_IO_PENDING) { |
| - write_pending_ = true; |
| - } else { |
| - HandleError(result); |
| - if (!write_failed_callback_.is_null()) |
| - write_failed_callback_.Run(result); |
| - } |
| + HandleError(result); |
| + if (!write_failed_callback_.is_null()) |
| + write_failed_callback_.Run(result); |
| + } |
| + return; |
| + } |
| + |
| + base::Closure done_task = AdvanceBufferPosition(result); |
| + if (!done_task.is_null()) { |
| + bool destroyed = false; |
| + destroyed_flag_ = &destroyed; |
| + done_task.Run(); |
| + destroyed_flag_ = NULL; |
|
simonmorris
2012/07/31 20:19:50
Isn't this use-after-free if the BufferedSocketWri
Sergey Ulanov
2012/07/31 21:37:53
Good catch. Fixed.
|
| + |
| + if (destroyed) { |
| + // Stop doing anything if we've been destroyed by the callback. |
| return; |
| } |
| } |
| + |
| + *write_again = true; |
| } |
| void BufferedSocketWriterBase::OnWritten(int result) { |
| DCHECK(CalledOnValidThread()); |
| + DCHECK(write_pending_); |
| write_pending_ = false; |
| - if (result < 0) { |
| - HandleError(result); |
| - if (!write_failed_callback_.is_null()) |
| - write_failed_callback_.Run(result); |
| - return; |
| - } |
| - |
| - AdvanceBufferPosition(result); |
| - |
| - DoWrite(); |
| + bool write_again; |
| + HandleWriteResult(result, &write_again); |
| + if (write_again) |
| + DoWrite(); |
| } |
| void BufferedSocketWriterBase::HandleError(int result) { |
| @@ -146,12 +156,18 @@ void BufferedSocketWriterBase::Close() { |
| closed_ = true; |
| } |
| -BufferedSocketWriterBase::~BufferedSocketWriterBase() {} |
| +BufferedSocketWriterBase::~BufferedSocketWriterBase() { |
| + if (destroyed_flag_) |
| + *destroyed_flag_ = true; |
| + |
| + STLDeleteElements(&queue_); |
| +} |
| -void BufferedSocketWriterBase::PopQueue() { |
| - // This also calls |done_task|. |
| +base::Closure BufferedSocketWriterBase::PopQueue() { |
| + base::Closure result = queue_.front()->done_task; |
| delete queue_.front(); |
| queue_.pop_front(); |
| + return result; |
| } |
| BufferedSocketWriter::BufferedSocketWriter() { |
| @@ -165,21 +181,22 @@ void BufferedSocketWriter::GetNextPacket( |
| return; // Nothing to write. |
| } |
| current_buf_ = new net::DrainableIOBuffer( |
| - queue_.front()->data(), queue_.front()->data()->size()); |
| + queue_.front()->data, queue_.front()->data->size()); |
| } |
| *buffer = current_buf_; |
| *size = current_buf_->BytesRemaining(); |
| } |
| -void BufferedSocketWriter::AdvanceBufferPosition(int written) { |
| +base::Closure BufferedSocketWriter::AdvanceBufferPosition(int written) { |
| buffer_size_ -= written; |
| current_buf_->DidConsume(written); |
| if (current_buf_->BytesRemaining() == 0) { |
| - PopQueue(); |
| current_buf_ = NULL; |
| + return PopQueue(); |
| } |
| + return base::Closure(); |
| } |
| void BufferedSocketWriter::OnError(int result) { |
| @@ -187,7 +204,6 @@ void BufferedSocketWriter::OnError(int result) { |
| } |
| BufferedSocketWriter::~BufferedSocketWriter() { |
| - STLDeleteElements(&queue_); |
| } |
| BufferedDatagramWriter::BufferedDatagramWriter() { |
| @@ -199,21 +215,22 @@ void BufferedDatagramWriter::GetNextPacket( |
| *buffer = NULL; |
| return; // Nothing to write. |
| } |
| - *buffer = queue_.front()->data(); |
| - *size = queue_.front()->data()->size(); |
| + *buffer = queue_.front()->data; |
| + *size = queue_.front()->data->size(); |
| } |
| -void BufferedDatagramWriter::AdvanceBufferPosition(int written) { |
| - DCHECK_EQ(written, queue_.front()->data()->size()); |
| - buffer_size_ -= queue_.front()->data()->size(); |
| - PopQueue(); |
| +base::Closure BufferedDatagramWriter::AdvanceBufferPosition(int written) { |
| + DCHECK_EQ(written, queue_.front()->data->size()); |
| + buffer_size_ -= queue_.front()->data->size(); |
| + return PopQueue(); |
| } |
| void BufferedDatagramWriter::OnError(int result) { |
| // Nothing to do here. |
| } |
| -BufferedDatagramWriter::~BufferedDatagramWriter() {} |
| +BufferedDatagramWriter::~BufferedDatagramWriter() { |
| +} |
| } // namespace protocol |
| } // namespace remoting |