Commit 6b302a86 authored by wez@chromium.org's avatar wez@chromium.org

Fix crash condition if caller deletes PseudoTcpAdaptor from within a callback.

BUG=82171
TEST=


Review URL: http://codereview.chromium.org/7040021

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@86570 0039d316-1c4b-4281-b951-d872f2087c98
parent 4115f132
...@@ -21,39 +21,106 @@ const uint16 kDefaultMtu = 1280; ...@@ -21,39 +21,106 @@ const uint16 kDefaultMtu = 1280;
namespace jingle_glue { namespace jingle_glue {
PseudoTcpAdapter::PseudoTcpAdapter(net::Socket* socket) class PseudoTcpAdapter::Core : public cricket::IPseudoTcpNotify,
: socket_(socket), public base::RefCounted<Core> {
ALLOW_THIS_IN_INITIALIZER_LIST(pseudotcp_(this, 0)), public:
connect_callback_(NULL), Core(net::Socket* socket);
virtual ~Core();
// Functions used to implement net::StreamSocket.
int Read(net::IOBuffer* buffer, int buffer_size,
net::CompletionCallback* callback);
int Write(net::IOBuffer* buffer, int buffer_size,
net::CompletionCallback* callback);
int Connect(net::CompletionCallback* callback);
void Disconnect();
bool IsConnected() const;
// cricket::IPseudoTcpNotify interface.
// These notifications are triggered from NotifyPacket.
virtual void OnTcpOpen(cricket::PseudoTcp* tcp) OVERRIDE;
virtual void OnTcpReadable(cricket::PseudoTcp* tcp) OVERRIDE;
virtual void OnTcpWriteable(cricket::PseudoTcp* tcp) OVERRIDE;
// This is triggered by NotifyClock or NotifyPacket.
virtual void OnTcpClosed(cricket::PseudoTcp* tcp, uint32 error) OVERRIDE;
// This is triggered by NotifyClock, NotifyPacket, Recv and Send.
virtual WriteResult TcpWritePacket(cricket::PseudoTcp* tcp,
const char* buffer, size_t len) OVERRIDE;
private:
// These are invoked by the underlying Socket, and may trigger callbacks.
// They hold a reference to |this| while running, to protect from deletion.
void OnRead(int result);
void OnWritten(int result);
// These may trigger callbacks, so the holder must hold a reference on
// the stack while calling them.
void DoReadFromSocket();
void HandleReadResults(int result);
void HandleTcpClock();
// This re-sets |timer| without triggering callbacks.
void AdjustClock();
net::CompletionCallback* connect_callback_;
net::CompletionCallback* read_callback_;
net::CompletionCallback* write_callback_;
cricket::PseudoTcp pseudo_tcp_;
scoped_ptr<net::Socket> socket_;
scoped_refptr<net::IOBuffer> read_buffer_;
int read_buffer_size_;
scoped_refptr<net::IOBuffer> write_buffer_;
int write_buffer_size_;
bool socket_write_pending_;
scoped_refptr<net::IOBuffer> socket_read_buffer_;
net::CompletionCallbackImpl<Core> socket_read_callback_;
net::CompletionCallbackImpl<Core> socket_write_callback_;
base::OneShotTimer<Core> timer_;
DISALLOW_COPY_AND_ASSIGN(Core);
};
PseudoTcpAdapter::Core::Core(net::Socket* socket)
: connect_callback_(NULL),
read_callback_(NULL), read_callback_(NULL),
write_callback_(NULL), write_callback_(NULL),
ALLOW_THIS_IN_INITIALIZER_LIST(pseudo_tcp_(this, 0)),
socket_(socket),
socket_write_pending_(false), socket_write_pending_(false),
ALLOW_THIS_IN_INITIALIZER_LIST( ALLOW_THIS_IN_INITIALIZER_LIST(
socket_read_callback_(this, &PseudoTcpAdapter::OnRead)), socket_read_callback_(this, &PseudoTcpAdapter::Core::OnRead)),
ALLOW_THIS_IN_INITIALIZER_LIST( ALLOW_THIS_IN_INITIALIZER_LIST(
socket_write_callback_(this, &PseudoTcpAdapter::OnWritten)) { socket_write_callback_(this, &PseudoTcpAdapter::Core::OnWritten)) {
pseudotcp_.NotifyMTU(kDefaultMtu); // Doesn't trigger callbacks.
pseudo_tcp_.NotifyMTU(kDefaultMtu);
} }
PseudoTcpAdapter::~PseudoTcpAdapter() { PseudoTcpAdapter::Core::~Core() {
} }
int PseudoTcpAdapter::Read(net::IOBuffer* buffer, int buffer_size, int PseudoTcpAdapter::Core::Read(net::IOBuffer* buffer, int buffer_size,
net::CompletionCallback* callback) { net::CompletionCallback* callback) {
DCHECK(CalledOnValidThread()); DCHECK(!read_callback_);
// Verify that there is no other pending read. // Reference the Core in case a callback deletes the adapter.
DCHECK(read_callback_ == NULL); scoped_refptr<Core> core(this);
PseudoTcp::TcpState state = pseudotcp_.State(); // TODO(wez): This is a hack for remoting. See JingleSession.
PseudoTcp::TcpState state = pseudo_tcp_.State();
int result; int result;
if (state == PseudoTcp::TCP_SYN_SENT || if (state == PseudoTcp::TCP_SYN_SENT ||
state == PseudoTcp::TCP_SYN_RECEIVED) { state == PseudoTcp::TCP_SYN_RECEIVED) {
result = net::ERR_IO_PENDING; result = net::ERR_IO_PENDING;
} else { } else {
result = pseudotcp_.Recv(buffer->data(), buffer_size); result = pseudo_tcp_.Recv(buffer->data(), buffer_size);
if (result < 0) { if (result < 0) {
result = net::MapSystemError(pseudotcp_.GetError()); result = net::MapSystemError(pseudo_tcp_.GetError());
DCHECK(result < 0); DCHECK(result < 0);
} }
} }
...@@ -69,22 +136,24 @@ int PseudoTcpAdapter::Read(net::IOBuffer* buffer, int buffer_size, ...@@ -69,22 +136,24 @@ int PseudoTcpAdapter::Read(net::IOBuffer* buffer, int buffer_size,
return result; return result;
} }
int PseudoTcpAdapter::Write(net::IOBuffer* buffer, int buffer_size, int PseudoTcpAdapter::Core::Write(net::IOBuffer* buffer, int buffer_size,
net::CompletionCallback* callback) { net::CompletionCallback* callback) {
DCHECK(CalledOnValidThread()); DCHECK(!write_callback_);
// Verify that there is no other pending write. // Reference the Core in case a callback deletes the adapter.
DCHECK(write_callback_ == NULL); scoped_refptr<Core> core(this);
PseudoTcp::TcpState state = pseudotcp_.State(); // TODO(wez): This is a hack for remoting. See JingleSession.
PseudoTcp::TcpState state = pseudo_tcp_.State();
int result; int result;
if (state == PseudoTcp::TCP_SYN_SENT || if (state == PseudoTcp::TCP_SYN_SENT ||
state == PseudoTcp::TCP_SYN_RECEIVED) { state == PseudoTcp::TCP_SYN_RECEIVED) {
result = net::ERR_IO_PENDING; result = net::ERR_IO_PENDING;
} else { } else {
result = pseudotcp_.Send(buffer->data(), buffer_size); result = pseudo_tcp_.Send(buffer->data(), buffer_size);
if (result < 0) { if (result < 0) {
result = net::MapSystemError(pseudotcp_.GetError()); result = net::MapSystemError(pseudo_tcp_.GetError());
DCHECK(result < 0); DCHECK(result < 0);
} }
} }
...@@ -100,114 +169,68 @@ int PseudoTcpAdapter::Write(net::IOBuffer* buffer, int buffer_size, ...@@ -100,114 +169,68 @@ int PseudoTcpAdapter::Write(net::IOBuffer* buffer, int buffer_size,
return result; return result;
} }
bool PseudoTcpAdapter::SetReceiveBufferSize(int32 size) { int PseudoTcpAdapter::Core::Connect(net::CompletionCallback* callback) {
DCHECK(CalledOnValidThread()); DCHECK_EQ(pseudo_tcp_.State(), cricket::PseudoTcp::TCP_LISTEN);
// TODO(sergeyu): Implement support for adjustable buffer size and
// used it here.
return false;
}
bool PseudoTcpAdapter::SetSendBufferSize(int32 size) {
DCHECK(CalledOnValidThread());
// TODO(sergeyu): Implement support for adjustable buffer size and
// used it here.
return false;
}
int PseudoTcpAdapter::Connect(net::CompletionCallback* callback) { // Reference the Core in case a callback deletes the adapter.
DCHECK(CalledOnValidThread()); scoped_refptr<Core> core(this);
// Start reading from the socket. // Start the connection attempt.
DoReadFromSocket(); int result = pseudo_tcp_.Connect();
int result = pseudotcp_.Connect();
if (result < 0) if (result < 0)
return net::ERR_FAILED; return net::ERR_FAILED;
AdjustClock(); AdjustClock();
connect_callback_ = callback; connect_callback_ = callback;
return net::ERR_IO_PENDING; DoReadFromSocket();
}
void PseudoTcpAdapter::Disconnect() {
DCHECK(CalledOnValidThread());
pseudotcp_.Close(false);
}
bool PseudoTcpAdapter::IsConnected() const {
DCHECK(CalledOnValidThread());
return pseudotcp_.State() == PseudoTcp::TCP_ESTABLISHED;
}
bool PseudoTcpAdapter::IsConnectedAndIdle() const {
DCHECK(CalledOnValidThread());
NOTIMPLEMENTED();
return false;
}
int PseudoTcpAdapter::GetPeerAddress(net::AddressList* address) const {
DCHECK(CalledOnValidThread());
// We actually don't know the peer address. Returning so the upper layers
// won't complain.
net::IPAddressNumber ip_address(4);
*address = net::AddressList::CreateFromIPAddress(ip_address, 0);
return net::OK;
}
int PseudoTcpAdapter::GetLocalAddress(net::IPEndPoint* address) const { return net::ERR_IO_PENDING;
DCHECK(CalledOnValidThread());
NOTIMPLEMENTED();
return net::ERR_FAILED;
} }
const net::BoundNetLog& PseudoTcpAdapter::NetLog() const { void PseudoTcpAdapter::Core::Disconnect() {
DCHECK(CalledOnValidThread()); // Don't dispatch outstanding callbacks, as mandated by net::StreamSocket.
return net_log_; read_callback_ = NULL;
} read_buffer_ = NULL;
write_callback_ = NULL;
write_buffer_ = NULL;
connect_callback_ = NULL;
void PseudoTcpAdapter::SetSubresourceSpeculation() { // TODO(wez): Connect should succeed if called after Disconnect, which
DCHECK(CalledOnValidThread()); // PseudoTcp doesn't support, so we need to teardown the internal PseudoTcp
NOTIMPLEMENTED(); // and create a new one in Connect.
// TODO(wez): Close sets a shutdown flag inside PseudoTcp but has no other
// effect. This should be addressed in PseudoTcp, really.
// In the meantime we can fake OnTcpClosed notification and tear down the
// PseudoTcp.
pseudo_tcp_.Close(true);
} }
void PseudoTcpAdapter::SetOmniboxSpeculation() { bool PseudoTcpAdapter::Core::IsConnected() const {
DCHECK(CalledOnValidThread()); return pseudo_tcp_.State() == PseudoTcp::TCP_ESTABLISHED;
NOTIMPLEMENTED();
}
bool PseudoTcpAdapter::WasEverUsed() const {
DCHECK(CalledOnValidThread());
NOTIMPLEMENTED();
return true;
} }
bool PseudoTcpAdapter::UsingTCPFastOpen() const { void PseudoTcpAdapter::Core::OnTcpOpen(PseudoTcp* tcp) {
DCHECK(CalledOnValidThread()); DCHECK(tcp == &pseudo_tcp_);
return false;
}
void PseudoTcpAdapter::OnTcpOpen(PseudoTcp* tcp) { if (connect_callback_) {
DCHECK(CalledOnValidThread()); net::CompletionCallback* callback = connect_callback_;
DCHECK(connect_callback_);
connect_callback_->Run(net::OK);
connect_callback_ = NULL; connect_callback_ = NULL;
callback->Run(net::OK);
}
OnTcpReadable(tcp); OnTcpReadable(tcp);
OnTcpWriteable(tcp); OnTcpWriteable(tcp);
} }
void PseudoTcpAdapter::OnTcpReadable(PseudoTcp* tcp) { void PseudoTcpAdapter::Core::OnTcpReadable(PseudoTcp* tcp) {
DCHECK(CalledOnValidThread()); DCHECK_EQ(tcp, &pseudo_tcp_);
if (!read_callback_)
if (!read_buffer_)
return; return;
// Try to send the data we have pending. int result = pseudo_tcp_.Recv(read_buffer_->data(), read_buffer_size_);
int result = pseudotcp_.Recv(read_buffer_->data(), read_buffer_size_);
if (result < 0) { if (result < 0) {
result = net::MapSystemError(pseudotcp_.GetError()); result = net::MapSystemError(pseudo_tcp_.GetError());
DCHECK(result < 0); DCHECK(result < 0);
if (result == net::ERR_IO_PENDING) if (result == net::ERR_IO_PENDING)
return; return;
...@@ -215,22 +238,20 @@ void PseudoTcpAdapter::OnTcpReadable(PseudoTcp* tcp) { ...@@ -215,22 +238,20 @@ void PseudoTcpAdapter::OnTcpReadable(PseudoTcp* tcp) {
AdjustClock(); AdjustClock();
net::CompletionCallback* cb = read_callback_; net::CompletionCallback* callback = read_callback_;
read_callback_ = NULL; read_callback_ = NULL;
read_buffer_ = NULL; read_buffer_ = NULL;
cb->Run(result); callback->Run(result);
} }
void PseudoTcpAdapter::OnTcpWriteable(PseudoTcp* tcp) { void PseudoTcpAdapter::Core::OnTcpWriteable(PseudoTcp* tcp) {
DCHECK(CalledOnValidThread()); DCHECK_EQ(tcp, &pseudo_tcp_);
if (!write_callback_)
if (!write_buffer_)
return; return;
// Try to send the data we have pending. int result = pseudo_tcp_.Send(write_buffer_->data(), write_buffer_size_);
int result = pseudotcp_.Send(write_buffer_->data(), write_buffer_size_);
if (result < 0) { if (result < 0) {
result = net::MapSystemError(pseudotcp_.GetError()); result = net::MapSystemError(pseudo_tcp_.GetError());
DCHECK(result < 0); DCHECK(result < 0);
if (result == net::ERR_IO_PENDING) if (result == net::ERR_IO_PENDING)
return; return;
...@@ -238,36 +259,39 @@ void PseudoTcpAdapter::OnTcpWriteable(PseudoTcp* tcp) { ...@@ -238,36 +259,39 @@ void PseudoTcpAdapter::OnTcpWriteable(PseudoTcp* tcp) {
AdjustClock(); AdjustClock();
net::CompletionCallback* cb = write_callback_; net::CompletionCallback* callback = write_callback_;
write_callback_ = NULL; write_callback_ = NULL;
write_buffer_ = NULL; write_buffer_ = NULL;
cb->Run(result); callback->Run(result);
} }
void PseudoTcpAdapter::OnTcpClosed(PseudoTcp* tcp, uint32 error) { void PseudoTcpAdapter::Core::OnTcpClosed(PseudoTcp* tcp, uint32 error) {
DCHECK(CalledOnValidThread()); DCHECK_EQ(tcp, &pseudo_tcp_);
if (connect_callback_) { if (connect_callback_) {
connect_callback_->Run(net::MapSystemError(error)); net::CompletionCallback* callback = connect_callback_;
connect_callback_ = NULL; connect_callback_ = NULL;
callback->Run(net::MapSystemError(error));
} }
if (read_callback_) { if (read_callback_) {
read_callback_->Run(net::MapSystemError(error)); net::CompletionCallback* callback = read_callback_;
read_callback_ = NULL; read_callback_ = NULL;
callback->Run(net::MapSystemError(error));
} }
if (write_callback_) { if (write_callback_) {
write_callback_->Run(net::MapSystemError(error)); net::CompletionCallback* callback = write_callback_;
write_callback_ = NULL; write_callback_ = NULL;
callback->Run(net::MapSystemError(error));
} }
} }
cricket::IPseudoTcpNotify::WriteResult PseudoTcpAdapter::TcpWritePacket( cricket::IPseudoTcpNotify::WriteResult PseudoTcpAdapter::Core::TcpWritePacket(
PseudoTcp* tcp, PseudoTcp* tcp,
const char* buffer, const char* buffer,
size_t len) { size_t len) {
DCHECK(CalledOnValidThread()); DCHECK_EQ(tcp, &pseudo_tcp_);
if (socket_write_pending_) if (socket_write_pending_)
return IPseudoTcpNotify::WR_SUCCESS; return IPseudoTcpNotify::WR_SUCCESS;
...@@ -288,10 +312,9 @@ cricket::IPseudoTcpNotify::WriteResult PseudoTcpAdapter::TcpWritePacket( ...@@ -288,10 +312,9 @@ cricket::IPseudoTcpNotify::WriteResult PseudoTcpAdapter::TcpWritePacket(
} }
} }
void PseudoTcpAdapter::DoReadFromSocket() { void PseudoTcpAdapter::Core::DoReadFromSocket() {
if (!socket_read_buffer_) { if (!socket_read_buffer_)
socket_read_buffer_ = new net::IOBuffer(kReadBufferSize); socket_read_buffer_ = new net::IOBuffer(kReadBufferSize);
}
while (true) { while (true) {
int result = socket_->Read(socket_read_buffer_, kReadBufferSize, int result = socket_->Read(socket_read_buffer_, kReadBufferSize,
...@@ -303,41 +326,154 @@ void PseudoTcpAdapter::DoReadFromSocket() { ...@@ -303,41 +326,154 @@ void PseudoTcpAdapter::DoReadFromSocket() {
} }
} }
void PseudoTcpAdapter::HandleReadResults(int result) { void PseudoTcpAdapter::Core::HandleReadResults(int result) {
if (result <= 0) { if (result <= 0) {
LOG(ERROR) << "Read returned " << result; LOG(ERROR) << "Read returned " << result;
return; return;
} }
pseudotcp_.NotifyPacket(socket_read_buffer_->data(), result); // TODO(wez): Disconnect on failure of NotifyPacket?
pseudo_tcp_.NotifyPacket(socket_read_buffer_->data(), result);
AdjustClock(); AdjustClock();
} }
void PseudoTcpAdapter::OnRead(int result) { void PseudoTcpAdapter::Core::OnRead(int result) {
// Reference the Core in case a callback deletes the adapter.
scoped_refptr<Core> core(this);
HandleReadResults(result); HandleReadResults(result);
if (result >= 0) if (result >= 0)
DoReadFromSocket(); DoReadFromSocket();
} }
void PseudoTcpAdapter::OnWritten(int result) { void PseudoTcpAdapter::Core::OnWritten(int result) {
// Reference the Core in case a callback deletes the adapter.
scoped_refptr<Core> core(this);
socket_write_pending_ = false; socket_write_pending_ = false;
if (result < 0) { if (result < 0) {
LOG(WARNING) << "Write failed. Error code: " << result; LOG(WARNING) << "Write failed. Error code: " << result;
} }
} }
void PseudoTcpAdapter::AdjustClock() { void PseudoTcpAdapter::Core::AdjustClock() {
long timeout = 0; long timeout = 0;
if (pseudotcp_.GetNextClock(PseudoTcp::Now(), timeout)) { if (pseudo_tcp_.GetNextClock(PseudoTcp::Now(), timeout)) {
timer_.Stop(); timer_.Stop();
timer_.Start(base::TimeDelta::FromMilliseconds(std::max(timeout, 0L)), this, timer_.Start(base::TimeDelta::FromMilliseconds(std::max(timeout, 0L)), this,
&PseudoTcpAdapter::HandleTcpClock); &PseudoTcpAdapter::Core::HandleTcpClock);
} }
} }
void PseudoTcpAdapter::HandleTcpClock() { void PseudoTcpAdapter::Core::HandleTcpClock() {
pseudotcp_.NotifyClock(PseudoTcp::Now()); // Reference the Core in case a callback deletes the adapter.
scoped_refptr<Core> core(this);
pseudo_tcp_.NotifyClock(PseudoTcp::Now());
AdjustClock(); AdjustClock();
} }
// Public interface implemention.
PseudoTcpAdapter::PseudoTcpAdapter(net::Socket* socket)
: core_(new Core(socket)) {
}
PseudoTcpAdapter::~PseudoTcpAdapter() {
Disconnect();
}
int PseudoTcpAdapter::Read(net::IOBuffer* buffer, int buffer_size,
net::CompletionCallback* callback) {
DCHECK(CalledOnValidThread());
return core_->Read(buffer, buffer_size, callback);
}
int PseudoTcpAdapter::Write(net::IOBuffer* buffer, int buffer_size,
net::CompletionCallback* callback) {
DCHECK(CalledOnValidThread());
return core_->Write(buffer, buffer_size, callback);
}
bool PseudoTcpAdapter::SetReceiveBufferSize(int32 size) {
DCHECK(CalledOnValidThread());
// TODO(sergeyu): Implement support for adjustable buffer size and
// used it here.
return false;
}
bool PseudoTcpAdapter::SetSendBufferSize(int32 size) {
DCHECK(CalledOnValidThread());
// TODO(sergeyu): Implement support for adjustable buffer size and
// used it here.
return false;
}
int PseudoTcpAdapter::Connect(net::CompletionCallback* callback) {
DCHECK(CalledOnValidThread());
// net::StreamSocket requires that Connect return OK if already connected.
if (IsConnected())
return net::OK;
return core_->Connect(callback);
}
void PseudoTcpAdapter::Disconnect() {
DCHECK(CalledOnValidThread());
core_->Disconnect();
}
bool PseudoTcpAdapter::IsConnected() const {
return core_->IsConnected();
}
bool PseudoTcpAdapter::IsConnectedAndIdle() const {
DCHECK(CalledOnValidThread());
NOTIMPLEMENTED();
return false;
}
int PseudoTcpAdapter::GetPeerAddress(net::AddressList* address) const {
DCHECK(CalledOnValidThread());
// We actually don't know the peer address. Returning so the upper layers
// won't complain.
net::IPAddressNumber ip_address(4);
*address = net::AddressList::CreateFromIPAddress(ip_address, 0);
return net::OK;
}
int PseudoTcpAdapter::GetLocalAddress(net::IPEndPoint* address) const {
DCHECK(CalledOnValidThread());
NOTIMPLEMENTED();
return net::ERR_FAILED;
}
const net::BoundNetLog& PseudoTcpAdapter::NetLog() const {
DCHECK(CalledOnValidThread());
return net_log_;
}
void PseudoTcpAdapter::SetSubresourceSpeculation() {
DCHECK(CalledOnValidThread());
NOTIMPLEMENTED();
}
void PseudoTcpAdapter::SetOmniboxSpeculation() {
DCHECK(CalledOnValidThread());
NOTIMPLEMENTED();
}
bool PseudoTcpAdapter::WasEverUsed() const {
DCHECK(CalledOnValidThread());
NOTIMPLEMENTED();
return true;
}
bool PseudoTcpAdapter::UsingTCPFastOpen() const {
DCHECK(CalledOnValidThread());
return false;
}
} // namespace jingle_glue } // namespace jingle_glue
...@@ -17,12 +17,15 @@ ...@@ -17,12 +17,15 @@
namespace jingle_glue { namespace jingle_glue {
class PseudoTcpAdapter : public net::StreamSocket, // PseudoTcpAdapter adapts a connectionless net::Socket to a connection-
public cricket::IPseudoTcpNotify, // oriented net::StreamSocket using PseudoTcp. Because net::StreamSockets
public base::NonThreadSafe { // can be deleted during callbacks, while PseudoTcp cannot, the core of the
// PseudoTcpAdapter is reference counted, with a reference held by the
// adapter, and an additional reference held on the stack during callbacks.
class PseudoTcpAdapter : public net::StreamSocket, base::NonThreadSafe {
public: public:
// Creates adapter for the specified |socket|. |socket| is assumed // Creates an adapter for the supplied Socket. |socket| should already
// to be already connected. Takes ownership of |socket|. // be ready for use, and ownership of it will be assumed by the adapter.
PseudoTcpAdapter(net::Socket* socket); PseudoTcpAdapter(net::Socket* socket);
virtual ~PseudoTcpAdapter(); virtual ~PseudoTcpAdapter();
...@@ -47,43 +50,10 @@ class PseudoTcpAdapter : public net::StreamSocket, ...@@ -47,43 +50,10 @@ class PseudoTcpAdapter : public net::StreamSocket,
virtual bool WasEverUsed() const OVERRIDE; virtual bool WasEverUsed() const OVERRIDE;
virtual bool UsingTCPFastOpen() const OVERRIDE; virtual bool UsingTCPFastOpen() const OVERRIDE;
// cricket::IPseudoTcpNotify implementation.
virtual void OnTcpOpen(cricket::PseudoTcp* tcp) OVERRIDE;
virtual void OnTcpReadable(cricket::PseudoTcp* tcp) OVERRIDE;
virtual void OnTcpWriteable(cricket::PseudoTcp* tcp) OVERRIDE;
virtual void OnTcpClosed(cricket::PseudoTcp* tcp, uint32 error) OVERRIDE;
virtual WriteResult TcpWritePacket(cricket::PseudoTcp* tcp,
const char* buffer, size_t len) OVERRIDE;
private: private:
void DoReadFromSocket(); class Core;
void HandleReadResults(int result);
// Callback functions for Read() and Write() in |socket_|
void OnRead(int result);
void OnWritten(int result);
void AdjustClock();
void HandleTcpClock();
scoped_ptr<net::Socket> socket_;
cricket::PseudoTcp pseudotcp_;
net::CompletionCallback* connect_callback_;
scoped_refptr<net::IOBuffer> read_buffer_;
int read_buffer_size_;
net::CompletionCallback* read_callback_;
scoped_refptr<net::IOBuffer> write_buffer_;
int write_buffer_size_;
net::CompletionCallback* write_callback_;
bool socket_write_pending_;
scoped_refptr<net::IOBuffer> socket_read_buffer_;
net::CompletionCallbackImpl<PseudoTcpAdapter> socket_read_callback_;
net::CompletionCallbackImpl<PseudoTcpAdapter> socket_write_callback_;
base::OneShotTimer<PseudoTcpAdapter> timer_; scoped_refptr<Core> core_;
net::BoundNetLog net_log_; net::BoundNetLog net_log_;
......
...@@ -307,6 +307,35 @@ TEST_F(P2PTransportImplTest, TestLossyChannel) { ...@@ -307,6 +307,35 @@ TEST_F(P2PTransportImplTest, TestLossyChannel) {
tester->CheckResults(); tester->CheckResults();
} }
class DeleteOnConnected {
public:
DeleteOnConnected(MessageLoop* message_loop,
scoped_ptr<PseudoTcpAdapter>* adapter)
: message_loop_(message_loop), adapter_(adapter) {}
void OnConnected(int error) {
adapter_->reset();
message_loop_->PostTask(FROM_HERE, new MessageLoop::QuitTask());
}
MessageLoop* message_loop_;
scoped_ptr<PseudoTcpAdapter>* adapter_;
};
TEST_F(P2PTransportImplTest, TestDeleteOnConnected) {
// This test verifies that deleting the adapter mid-callback doesn't lead
// to deleted structures being touched as the stack unrolls, so the failure
// mode is a crash rather than a normal test failure.
TestCompletionCallback client_connect_cb;
DeleteOnConnected host_delete(&message_loop_, &host_pseudotcp_);
net::CompletionCallbackImpl<DeleteOnConnected>
host_connect_cb(&host_delete, &DeleteOnConnected::OnConnected);
host_pseudotcp_->Connect(&host_connect_cb);
client_pseudotcp_->Connect(&client_connect_cb);
message_loop_.Run();
ASSERT_EQ(NULL, host_pseudotcp_.get());
}
} // namespace } // namespace
} // namespace jingle_glue } // namespace jingle_glue
...@@ -381,6 +381,8 @@ bool JingleSession::EstablishSSLConnection( ...@@ -381,6 +381,8 @@ bool JingleSession::EstablishSSLConnection(
new jingle_glue::PseudoTcpAdapter(channel); new jingle_glue::PseudoTcpAdapter(channel);
pseudotcp->Connect(&connect_callback_); pseudotcp->Connect(&connect_callback_);
// TODO(wez): We shouldn't try to start SSL until the socket we're
// starting it on is connected.
if (cricket_session_->initiator()) { if (cricket_session_->initiator()) {
// Create client SSL socket. // Create client SSL socket.
net::SSLClientSocket* socket = CreateSSLClientSocket( net::SSLClientSocket* socket = CreateSSLClientSocket(
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment