| Index: remoting/jingle_glue/jingle_channel.cc
|
| diff --git a/remoting/jingle_glue/jingle_channel.cc b/remoting/jingle_glue/jingle_channel.cc
|
| index 0ff634c383f16dec3e011bf94c3016e169a2b9fb..9dc545fba4e711df559f87267b90616756170d93 100644
|
| --- a/remoting/jingle_glue/jingle_channel.cc
|
| +++ b/remoting/jingle_glue/jingle_channel.cc
|
| @@ -22,6 +22,7 @@ const size_t kReadBufferSize = 4096;
|
| JingleChannel::JingleChannel(Callback* callback)
|
| : state_(INITIALIZING),
|
| callback_(callback),
|
| + closed_(false),
|
| event_handler_(this),
|
| write_buffer_size_(0),
|
| current_write_buf_pos_(0) {
|
| @@ -31,12 +32,13 @@ JingleChannel::JingleChannel(Callback* callback)
|
| // This constructor is only used in unit test.
|
| JingleChannel::JingleChannel()
|
| : state_(CLOSED),
|
| + closed_(false),
|
| write_buffer_size_(0),
|
| current_write_buf_pos_(0) {
|
| }
|
|
|
| JingleChannel::~JingleChannel() {
|
| - DCHECK_EQ(CLOSED, state_);
|
| + DCHECK(closed_ || stream_ == NULL);
|
| }
|
|
|
| void JingleChannel::Init(JingleThread* thread,
|
| @@ -101,7 +103,12 @@ void JingleChannel::DoRead() {
|
| case talk_base::SR_SUCCESS: {
|
| DCHECK_GT(bytes_read, 0U);
|
| buffer->SetDataSize(bytes_read);
|
| - callback_->OnPacketReceived(this, buffer);
|
| + {
|
| + AutoLock auto_lock(state_lock_);
|
| + // Drop received data if the channel is already closed.
|
| + if (!closed_)
|
| + callback_->OnPacketReceived(this, buffer);
|
| + }
|
| break;
|
| }
|
| case talk_base::SR_BLOCK: {
|
| @@ -177,25 +184,53 @@ void JingleChannel::OnStreamEvent(talk_base::StreamInterface* stream,
|
| SetState(CLOSED);
|
| }
|
|
|
| -void JingleChannel::SetState(State state) {
|
| - if (state == state_)
|
| - return;
|
| - state_ = state;
|
| - callback_->OnStateChange(this, state);
|
| +void JingleChannel::SetState(State new_state) {
|
| + if (new_state != state_) {
|
| + state_ = new_state;
|
| + {
|
| + AutoLock auto_lock(state_lock_);
|
| + if (!closed_)
|
| + callback_->OnStateChange(this, new_state);
|
| + }
|
| + }
|
| }
|
|
|
| void JingleChannel::Close() {
|
| - base::WaitableEvent event(true, false);
|
| + Close(NULL);
|
| +}
|
| +
|
| +void JingleChannel::Close(Task* closed_task) {
|
| + {
|
| + AutoLock auto_lock(state_lock_);
|
| + if (closed_) {
|
| + // We are already closed.
|
| + if (closed_task)
|
| + thread_->message_loop()->PostTask(FROM_HERE, closed_task);
|
| + return;
|
| + }
|
| + closed_ = true;
|
| + if (closed_task)
|
| + closed_task_.reset(closed_task);
|
| + }
|
| +
|
| thread_->message_loop()->PostTask(
|
| - FROM_HERE, NewRunnableMethod(this, &JingleChannel::DoClose, &event));
|
| - event.Wait();
|
| + FROM_HERE, NewRunnableMethod(this, &JingleChannel::DoClose));
|
| }
|
|
|
| -void JingleChannel::DoClose(base::WaitableEvent* done_event) {
|
| - if (stream_.get())
|
| - stream_->Close();
|
| - SetState(CLOSED);
|
| - done_event->Signal();
|
| +
|
| +void JingleChannel::DoClose() {
|
| + DCHECK(closed_);
|
| + stream_->Close();
|
| + stream_.reset();
|
| +
|
| + // TODO(sergeyu): Even though we have called Close() for the stream, it
|
| + // doesn't mean that the p2p sessions has been closed. I.e. |closed_task_|
|
| + // is called too early. If the client is closed right after that the other
|
| + // side will not receive notification that the channel was closed.
|
| + if (closed_task_.get()) {
|
| + closed_task_->Run();
|
| + closed_task_.reset();
|
| + }
|
| }
|
|
|
| size_t JingleChannel::write_buffer_size() {
|
|
|